{%- comment -%} MIT License · (c) 2026 Lintel · https://lintelagency.com/resources/shopify-sections {%- endcomment -%} {%- comment -%} Video gallery: a grid of video tiles (one block each: a Shopify-hosted video or a YouTube/Vimeo link, a poster image, a title and an optional caption such as the length). A tile opens the video in one shared lightbox (a native modal : labelled, closes with Esc, the close button or a click on the backdrop, focus goes back to the tile). Nothing third-party loads with the page: the player is created on click (YouTube through youtube-nocookie.com, Vimeo with dnt=1) and removed on close. Without JavaScript each tile is a plain link to the video. Depends on: none {%- endcomment -%} {%- liquid assign s = section.settings assign heading_tag = s.heading_tag | default: 'h2' assign dialog_title_id = 'LibVideoGalleryTitle-' | append: section.id assign play_label = s.play_label | default: 'Play video' | escape -%}
{%- if s.heading != blank or s.text != blank -%}
{%- if s.heading != blank -%} <{{ heading_tag }} class="lib-vgallery__heading lib-vgallery__heading--{{ s.heading_size }}"> {{- s.heading -}} {%- endif -%} {%- if s.text != blank -%}
{{ s.text }}
{%- endif -%}
{%- endif -%}
    {%- for block in section.blocks -%} {%- liquid assign b = block.settings assign src_type = '' assign src_id = '' assign href = '' assign embed = '' assign ratio = '16 / 9' if b.video != blank assign src_type = 'shopify' for source in b.video.sources if source.mime_type == 'video/mp4' assign href = source.url break endif endfor if b.video.aspect_ratio != blank assign ratio = b.video.aspect_ratio endif elsif b.video_url != blank assign src_type = b.video_url.type assign src_id = b.video_url.id if src_type == 'youtube' assign href = 'https://www.youtube.com/watch?v=' | append: src_id assign embed = 'https://www.youtube-nocookie.com/embed/' | append: src_id | append: '?autoplay=1&playsinline=1&rel=0' elsif src_type == 'vimeo' assign href = 'https://vimeo.com/' | append: src_id assign embed = 'https://player.vimeo.com/video/' | append: src_id | append: '?dnt=1&autoplay=1' endif endif assign poster = b.poster if poster == blank and src_type == 'shopify' assign poster = b.video.preview_image endif assign title = b.title | default: 'Video' | escape -%}
  • {%- capture tile_inner -%} {%- if poster != blank -%} {{ poster | image_url: width: 1200 | image_tag: class: 'lib-vgallery__img', loading: 'lazy', alt: '', sizes: '(min-width: 990px) 33vw, (min-width: 750px) 50vw, 100vw', widths: '400, 600, 800, 1000, 1200' }} {%- else -%} {{ 'lifestyle-1' | placeholder_svg_tag: 'lib-vgallery__img' }} {%- endif -%} {{ title }} {%- if b.caption != blank -%} {{ b.caption | escape }} {%- endif -%} {%- endcapture -%} {%- if href != blank -%} {{- tile_inner -}} {%- else -%}
    {{- tile_inner -}}
    {%- endif -%}
  • {%- endfor -%}

{% stylesheet %} .lib-vgallery { background-color: var(--lib-bg); background-image: var(--lib-bg-image, none); color: var(--lib-text); padding: var(--lib-pt) 1rem var(--lib-pb); } .lib-vgallery__inner { display: block; max-width: 1200px; margin: 0 auto; } .lib-vgallery--full .lib-vgallery__inner { max-width: none; } @media (max-width: 749px) { .lib-vgallery { padding-top: var(--lib-pt-m); padding-bottom: var(--lib-pb-m); } .lib-vgallery[data-show='desktop'] { display: none; } } @media (min-width: 750px) { .lib-vgallery[data-show='mobile'] { display: none; } } .lib-vgallery__header { display: flex; flex-direction: column; align-items: flex-start; text-align: left; margin-bottom: clamp(1.75rem, 4vw, 2.75rem); } .lib-vgallery__header[data-align='center'] { align-items: center; text-align: center; } .lib-vgallery__header[data-align='right'] { align-items: flex-end; text-align: right; } @media (max-width: 749px) { .lib-vgallery__header[data-align-m='left'] { align-items: flex-start; text-align: left; } .lib-vgallery__header[data-align-m='center'] { align-items: center; text-align: center; } .lib-vgallery__header[data-align-m='right'] { align-items: flex-end; text-align: right; } } .lib-vgallery__heading { margin: 0; font-size: clamp(1.75rem, 3.4vw, 2.75rem); line-height: 1.1; letter-spacing: -0.02em; text-wrap: balance; } .lib-vgallery__heading--small { font-size: clamp(1.375rem, 2.2vw, 1.75rem); } .lib-vgallery__heading--medium { font-size: clamp(1.5rem, 2.8vw, 2.25rem); } .lib-vgallery__heading--xlarge { font-size: clamp(2.25rem, 5vw, 3.75rem); } .lib-vgallery__text { margin-top: 0.875rem; max-width: 40rem; font-size: 1.0625rem; line-height: 1.6; opacity: 0.82; } .lib-vgallery__text > :first-child { margin-top: 0; } .lib-vgallery__text > :last-child { margin-bottom: 0; } .lib-vgallery__grid { display: grid; grid-template-columns: repeat(var(--lib-cols-m), minmax(0, 1fr)); gap: clamp(1rem, 2.5vw, 1.75rem); margin: 0; padding: 0; list-style: none; } @media (min-width: 750px) { .lib-vgallery__grid { grid-template-columns: repeat(min(var(--lib-cols), 2), minmax(0, 1fr)); } } @media (min-width: 990px) { .lib-vgallery__grid { grid-template-columns: repeat(var(--lib-cols), minmax(0, 1fr)); } } .lib-vgallery__tile { display: flex; flex-direction: column; gap: 0.875rem; color: inherit; text-decoration: none; border-radius: var(--lib-radius-img); } .lib-vgallery__tile:focus-visible { outline: 2px solid var(--lib-accent); outline-offset: 4px; } .lib-vgallery__poster { position: relative; display: block; overflow: hidden; border-radius: var(--lib-radius-img); aspect-ratio: 16 / 9; background: color-mix(in srgb, var(--lib-text) 8%, transparent); } .lib-vgallery[data-ratio='square'] .lib-vgallery__poster { aspect-ratio: 1; } .lib-vgallery[data-ratio='portrait'] .lib-vgallery__poster { aspect-ratio: 4 / 5; } .lib-vgallery__img { display: block; width: 100%; height: 100%; object-fit: cover; } .lib-vgallery__img:is(svg) { fill: color-mix(in srgb, var(--lib-text) 25%, transparent); } .lib-vgallery__play { position: absolute; inset: 50% auto auto 50%; display: grid; place-items: center; width: 3.5rem; height: 3.5rem; margin: -1.75rem 0 0 -1.75rem; border-radius: 50%; background: var(--lib-accent); color: var(--lib-accent-text); box-shadow: 0 10px 24px -10px rgb(0 0 0 / 0.5); } .lib-vgallery__play svg { margin-left: 3px; } .lib-vgallery__meta { display: grid; gap: 0.25rem; } .lib-vgallery__title { font-weight: 600; font-size: 1.0625rem; line-height: 1.35; } .lib-vgallery__caption { font-size: 0.9375rem; opacity: 0.75; } @media (prefers-reduced-motion: no-preference) { .lib-vgallery__img, .lib-vgallery__play { transition: transform 0.4s ease; } .lib-vgallery__tile:hover .lib-vgallery__img { transform: scale(1.03); } .lib-vgallery__tile:hover .lib-vgallery__play { transform: scale(1.08); } } /* Lightbox */ .lib-vgallery__dialog { width: 100vw; max-width: none; height: 100vh; max-height: none; margin: 0; padding: 4.5rem 1rem 2rem; border: 0; background: transparent; color: #fff; } .lib-vgallery__dialog[open] { display: grid; grid-template-rows: auto 1fr; justify-items: center; align-items: center; } .lib-vgallery__dialog::backdrop { background: rgb(12 10 9 / 0.9); } .lib-vgallery__dialog-title { position: absolute; top: 1.25rem; left: 1.25rem; right: 4.5rem; margin: 0; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .lib-vgallery__frame { grid-row: 2; width: min(100%, 1280px, calc((100vh - 7rem) * (var(--lib-dialog-ratio, 16 / 9)))); aspect-ratio: var(--lib-dialog-ratio, 16 / 9); background: #000; } .lib-vgallery__media { display: block; width: 100%; height: 100%; border: 0; } .lib-vgallery__close { position: absolute; top: 0.75rem; right: 0.75rem; display: grid; place-items: center; width: 2.75rem; height: 2.75rem; border: 0; border-radius: 50%; background: rgb(255 255 255 / 0.14); color: #fff; cursor: pointer; } .lib-vgallery__close:hover { background: rgb(255 255 255 / 0.24); } .lib-vgallery__close:focus-visible { outline: 2px solid #fff; outline-offset: 2px; } @supports (animation-timeline: view()) { @media (prefers-reduced-motion: no-preference) { .lib-vgallery[data-animate] .lib-vgallery__item { animation: lib-vgallery-rise linear both; animation-timeline: view(); animation-range: entry 0% entry 60%; } } } @keyframes lib-vgallery-rise { from { opacity: 0; transform: translateY(24px); } } {% endstylesheet %} {% javascript %} if (!customElements.get('lib-video-gallery')) { customElements.define( 'lib-video-gallery', class extends HTMLElement { connectedCallback() { if (this._ready) return; this.dialog = this.querySelector('.lib-vgallery__dialog'); if (!this.dialog || typeof this.dialog.showModal !== 'function') return; this._ready = true; this.frame = this.dialog.querySelector('.lib-vgallery__frame'); this.titleEl = this.dialog.querySelector('.lib-vgallery__dialog-title'); this.closeBtn = this.dialog.querySelector('.lib-vgallery__close'); this.tiles = Array.from(this.querySelectorAll('a.lib-vgallery__tile')); this.tiles.forEach((tile) => tile.setAttribute('aria-haspopup', 'dialog')); this.onClick = (event) => { const tile = event.target.closest('a.lib-vgallery__tile'); if (!tile || !this.contains(tile)) return; if (event.metaKey || event.ctrlKey || event.shiftKey || event.button === 1) return; event.preventDefault(); this.open(tile); }; this.onClose = () => this.closed(); this.onCloseBtn = () => this.dialog.close(); this.onBackdrop = (event) => { if (event.target === this.dialog) this.dialog.close(); }; this.addEventListener('click', this.onClick); this.dialog.addEventListener('close', this.onClose); this.dialog.addEventListener('click', this.onBackdrop); this.closeBtn.addEventListener('click', this.onCloseBtn); } disconnectedCallback() { if (!this._ready) return; this._ready = false; this.removeEventListener('click', this.onClick); this.dialog.removeEventListener('close', this.onClose); this.dialog.removeEventListener('click', this.onBackdrop); this.closeBtn.removeEventListener('click', this.onCloseBtn); if (this.dialog.open) this.dialog.close(); } // The player comes from the tile's inert template, so nothing loads before this click. open(tile) { const tpl = tile.nextElementSibling; if (!tpl || tpl.tagName !== 'TEMPLATE') return; this.opener = tile; this.titleEl.textContent = tile.dataset.title || ''; this.dialog.style.setProperty('--lib-dialog-ratio', tile.dataset.ratio || '16 / 9'); this.frame.replaceChildren(tpl.content.cloneNode(true)); this.dialog.showModal(); this.closeBtn.focus(); const video = this.frame.querySelector('video'); if (video) { const playing = video.play(); if (playing && playing.catch) playing.catch(() => {}); } } // Removing the player stops playback and any third-party connection it opened. closed() { this.frame.replaceChildren(); if (this.opener && this.opener.isConnected) this.opener.focus(); this.opener = null; } } ); } {% endjavascript %} {% schema %} { "name": "Lib · Video gallery", "tag": "section", "class": "lib-section", "max_blocks": 12, "settings": [ { "type": "header", "content": "Heading" }, { "type": "inline_richtext", "id": "heading", "label": "Heading", "default": "Inside the studio" }, { "type": "select", "id": "heading_tag", "label": "Heading tag", "info": "Use H1 only when this is the page's main heading.", "options": [ { "value": "h1", "label": "H1" }, { "value": "h2", "label": "H2" }, { "value": "h3", "label": "H3" }, { "value": "p", "label": "Paragraph" } ], "default": "h2" }, { "type": "select", "id": "heading_size", "label": "Heading size", "options": [ { "value": "small", "label": "Small" }, { "value": "medium", "label": "Medium" }, { "value": "large", "label": "Large" }, { "value": "xlarge", "label": "Extra large" } ], "default": "large" }, { "type": "richtext", "id": "text", "label": "Text", "default": "

Short films from the wheel, the kiln and the packing table.

" }, { "type": "header", "content": "Grid" }, { "type": "range", "id": "columns_desktop", "label": "Columns on desktop", "min": 2, "max": 4, "step": 1, "default": 3 }, { "type": "select", "id": "columns_mobile", "label": "Columns on mobile", "options": [ { "value": "1", "label": "1" }, { "value": "2", "label": "2" } ], "default": "1" }, { "type": "select", "id": "tile_ratio", "label": "Poster shape", "options": [ { "value": "landscape", "label": "Landscape (16:9)" }, { "value": "square", "label": "Square" }, { "value": "portrait", "label": "Portrait (4:5)" } ], "default": "landscape" }, { "type": "range", "id": "image_radius", "label": "Poster corner radius", "min": 0, "max": 32, "step": 2, "unit": "px", "default": 12 }, { "type": "header", "content": "Words for shoppers and screen readers" }, { "type": "text", "id": "play_label", "label": "Play label", "info": "Read before each video's title.", "default": "Play video" }, { "type": "text", "id": "close_label", "label": "Close button label", "default": "Close video" }, { "type": "header", "content": "Layout" }, { "type": "select", "id": "section_width", "label": "Width", "options": [ { "value": "page", "label": "Page width" }, { "value": "full", "label": "Full width" } ], "default": "page" }, { "type": "text_alignment", "id": "text_alignment", "label": "Heading alignment on desktop", "default": "left" }, { "type": "select", "id": "text_alignment_mobile", "label": "Heading alignment on mobile", "options": [ { "value": "left", "label": "Left" }, { "value": "center", "label": "Center" }, { "value": "right", "label": "Right" } ], "default": "left" }, { "type": "header", "content": "Colors" }, { "type": "color", "id": "color_bg", "label": "Background", "default": "#F4EFE8" }, { "type": "color_background", "id": "color_bg_gradient", "label": "Background gradient", "info": "Optional. Covers the background color." }, { "type": "color", "id": "color_text", "label": "Text", "default": "#2A2420" }, { "type": "color", "id": "color_accent", "label": "Accent (play button, focus ring)", "default": "#2A2420" }, { "type": "color", "id": "color_accent_text", "label": "Text on accent", "default": "#FFFFFF" }, { "type": "header", "content": "Spacing and visibility" }, { "type": "range", "id": "padding_top", "label": "Top padding on desktop", "min": 0, "max": 200, "step": 4, "unit": "px", "default": 80 }, { "type": "range", "id": "padding_bottom", "label": "Bottom padding on desktop", "min": 0, "max": 200, "step": 4, "unit": "px", "default": 80 }, { "type": "range", "id": "padding_top_mobile", "label": "Top padding on mobile", "min": 0, "max": 160, "step": 4, "unit": "px", "default": 48 }, { "type": "range", "id": "padding_bottom_mobile", "label": "Bottom padding on mobile", "min": 0, "max": 160, "step": 4, "unit": "px", "default": 48 }, { "type": "select", "id": "show_on", "label": "Show on", "options": [ { "value": "all", "label": "All devices" }, { "value": "desktop", "label": "Desktop only" }, { "value": "mobile", "label": "Mobile only" } ], "default": "all" }, { "type": "text", "id": "anchor_id", "label": "Anchor ID", "info": "Optional. Link to this section with #your-id." }, { "type": "header", "content": "Motion" }, { "type": "checkbox", "id": "animate", "label": "Rise in on scroll", "info": "Only in browsers that support scroll-driven animations; never when reduced motion is on.", "default": false } ], "blocks": [ { "type": "video", "name": "Video", "settings": [ { "type": "video", "id": "video", "label": "Shopify-hosted video", "info": "Upload in Content > Files. Used before the link below." }, { "type": "video_url", "id": "video_url", "label": "Or a YouTube or Vimeo link", "accept": ["youtube", "vimeo"], "info": "Loads only when a shopper plays it (youtube-nocookie.com, Vimeo with Do Not Track)." }, { "type": "image_picker", "id": "poster", "label": "Poster image", "info": "Needed for YouTube and Vimeo. Shopify videos use their own preview image when empty." }, { "type": "text", "id": "title", "label": "Title", "default": "Video title" }, { "type": "text", "id": "caption", "label": "Caption", "info": "Optional, for example the length: 2 min." } ] } ], "presets": [ { "name": "Lib · Video gallery", "blocks": [ { "type": "video", "settings": { "title": "Throwing a vase" } }, { "type": "video", "settings": { "title": "Glazing day" } }, { "type": "video", "settings": { "title": "Packing an order" } } ] } ] } {% endschema %}