Homepage Hero Carousel v2: Video and Split-Image Slides With Per-Slide Typography Control
The live homepage hero: two independent carousels over one authored slide list, video slides and split-image slides, typography controlled per slide, and promotion events fired from the slide's own copy.
A campaign hero has to be two compositions — a two-image split on desktop, a single crop on a phone — and one responsive DOM cannot be both. This section renders one authored slide list twice, as a desktop carousel and a mobile carousel, namespaces every selector and control id by section id so the two never cross-wire, and fires GA4 promotion events carrying the slide text the merchandiser typed.
The Problem
The homepage hero is the most contested piece of real estate a direct-to-consumer brand owns. It changes for every drop, it is the first thing a paid click lands on, and the people who decide what it says are not the people who can deploy a theme.
Two things made the previous heroes unequal to that. They supported one fixed layout, so a campaign whose desktop art was a two-image split and whose mobile art was a single crop had to pick one and compromise the other. And nothing about a slide's type — family, size, weight, line height, letter spacing — was a setting, so a comp that specified a headline treatment arrived as a code change. A Shopify section can only be authored through the settings it declares. Anything it does not declare is a developer's afternoon.
The Constraint
One section had to serve two genuinely different compositions. The desktop layout is two images side by side at a merchandiser-chosen ratio; mobile is one crop with the copy sitting over it. That is not a reflow — no arrangement of CSS on a single DOM produces both from the same elements, because the elements are not the same.
Every carousel on the page shares a single Swiper instance, so any selector this section uses has to be namespaced to the section itself. Two hero sections on one page, or a theme-editor re-render, must not leave one carousel driving another's slides.
And there is no data layer behind this hero. No metafields, no metaobjects: everything a merchandiser can change has to be a section-block setting, which means the schema has to carry the entire vocabulary of the design up front, before anyone knows what the next campaign looks like.
What We Built
index-header-slider2.liquid renders two independent Swiper carousels — .desktop-header-slider-v2-{section.id} and .mobile-header-slider-v2-{section.id} — each looping the same section.blocks. One authored list, two compositions.
Two block types. A video_slide carries a desktop video, a mobile video and cover images, rendered through Shopify's video_tag filter with autoplay, loop and muted set, wrapped in an anchor whose accessible name is composed by a helper snippet rather than typed per slide. A slider block carries image1, image2 and imagem — desktop left, desktop right, mobile — with a banner_image_width setting holding the split as a ratio like 60-40, a solid-colour substitute available for either desktop image, and a swap_images toggle that reverses the order without re-uploading anything.
Where the art direction lives. Hero images are emitted as CSS background-image at an image_url width of 3840 rather than as <img> elements, so a campaign's crop and focal point are handled by background positioning, per breakpoint, rather than by an object-fit rule the merchandiser cannot reach.
Slide copy. Each block carries between 59 and 66 settings, covering pre-title, title and description with independent font family, size, weight, line height and letter spacing for desktop and mobile; button label, URL, background, hover and text colours; content position and alignment; an offer-details tooltip; and a per-slide sticky banner. All of it is rendered by a shared custom-banner snippet keyed by the slide's uid — the renderer documented on its own page. Video slides mount the <play-pause> element covered on the video play/pause page, again keyed by uid, so each slide's control targets its own video.
Promotion tracking. An IntersectionObserver at a 0.5 threshold fires a GA4 view_promotion event as a slide comes into view, carrying creative_name of homepage-carousel, the slot index, and the slide's own text — harvested into a data-slide-content attribute at render time through strip_html and strip_newlines, so the promotion name in the report is the copy the merchandiser wrote. Each CTA fires select_promotion on click. When the section is first on the page, its first-slide images take fetchpriority="high".
Why This Way
Two carousels beat one responsive carousel because the two compositions are not the same elements. A single DOM would have had to carry the split-image pair and the mobile crop together and hide one of them, which means authoring every campaign twice into one slide anyway.
Exposing typography per slide is the deliberate part. Campaign art direction changes every drop, and the alternative is a developer edit per campaign — which is how a hero becomes the section everyone is afraid to touch. Putting the type spec in the editor moves the work to the person who has the comp open.
Both choices have a bill. The slide markup exists twice in the document at every breakpoint, once per carousel, which is real weight on the page that matters most for a paid landing. And because the art is a CSS background-image rather than an <img>, the browser's own responsive-image machinery is out of the loop: the source set is a decision the section makes at render, not one the browser makes from srcset. We took both to get art direction a merchandiser can actually perform.
Why Not an App
Slider and page-builder apps — Shogun, PageFly and the slide-anything class of app — do this job, and for a store without a theme team they are the right answer.
The shape does not suit a hero this contested. An app owns the markup it renders and brings its own runtime, which puts the most valuable content on the site outside the theme and outside version control. It also puts the promotion tracking somewhere else: an app's own analytics events describe the app's slides, not the storefront's. Here the events carry the same slide text that renders in the HTML, because both come from the same block setting in the same file.
Implementation Notes
- Swiper is initialised twice per section, against
section.id-namespaced selectors, so two placements of the section on one page cannot cross-wire their carousels or their pagination. - The desktop carousel sets
allowTouchMove: falsewhile the mobile one sets it true withgrabCursor— a deliberate divergence, since a desktop drag competes with text selection on a slide that is mostly copy. - Hero images are emitted as CSS
background-imageat animage_urlwidth of 3840, which is what makes per-breakpoint art direction a background-position decision rather than a crop baked into the asset. - The per-slide uid is
desktop-ormobile-, plusforloop.index, plussection.id, and it is threaded into the content renderer and the play/pause control so every slide's furniture is uniquely addressable. data-slide-contentis built withstrip_html | strip_newlines | replace ' ', ' ', so the promotion name arriving in GA4 is clean single-spaced text rather than the slide's markup with its line breaks intact.- The IntersectionObserver construction is wrapped in
try/catch, so a browser that cannot construct one loses the promotion event and keeps the hero, rather than throwing inside the section's own script. fetch_priorityis set tohighonly whensection.index == 1, keeping the priority hint on the hero that is genuinely first rather than on every instance of the section.- Video slides go through Shopify's
video_tagfilter rather than a hand-written<video>, so Shopify serves the poster and the source ladder at animage_sizeof 1500 wide.
Edge Cases
- Solid-colour substitutes (
image1_use_solid_bg,image2_use_solid_bg,mobile_use_solid_bg) let a slide ship with a colour block where artwork has not arrived yet, which is how a campaign goes live on schedule. - An empty image slot falls back to
placeholder_svg_tag, so a half-built slide in the theme editor still lays out at the right proportions instead of collapsing to nothing. swap_imagesreverses the desktop split without re-uploading either asset, so a late art-direction change is a toggle rather than a re-export.- A video slide only renders its play/pause control when a video is actually set, so an image slide never ships a control with nothing behind it.
- Navigation arrows and pagination are gated behind the
showcontensetting, letting a single-slide hero render without dead carousel furniture. - A slide renders as an anchor only when a URL is present, and its accessible name is derived from the destination rather than left as bare link text.
Platform Primitives Used
liquid-schema-settings— the whole authoring surface. Every layout, colour and type control on a slide is a block setting resolved in Liquid at render.intersection-observer— the slide-impression trigger, at a 0.5 threshold, so a promotion counts as seen when half of it is on screen.datalayer—view_promotionandselect_promotionare pushed with the slot index and the slide's own copy as the promotion name.
Integrations in Play
- Swiper — the carousel library both instances run on. The section wraps it rather than replacing it, and namespaces its selectors so it can be mounted more than once.
- Google Tag Manager — the promotion events are pushed to the
dataLayerfor the site's tag manager to forward to GA4. The section emits the events; it does not own the reporting.
Where It Runs
The home page, on one template — index — from a single section file. Because every selector and control id is namespaced by section.id, the section is placeable more than once on a page rather than being a homepage-only singleton, which is what makes it reusable for a campaign landing page later.
What This Demonstrates
- Art-directed hero and banner system — the primary capability, in its hardest form: two compositions from one authored slide, with the crop and the type spec both in the merchandiser's hands.
- Campaign landing pages without a page builder — the hero is a theme section in version control, so a campaign ships from the theme editor rather than from an app's canvas.
- Analytics and dataLayer instrumentation — promotion events wired to the same block settings that render the slide, so the report and the page cannot disagree about what was shown.
How We Know
One section file read from the theme, roughly 1,700 lines, plus specification documents and task-register entries from client working sessions. The record around this hero is unusually thick: the version it replaced accounted for a long run of logged fixes — headline, height, colour, an added button, video behaviour — before a phase-one specification set the target shape, which named a fifty-fifty layout with a solid-colour backdrop chosen in the Shopify editor, a photo on one side, and a pause and play control for video backgrounds. This section is that specification, built. The two-carousel decision and the uid convention are code-side, read from the file.
Related Builds
- Hero slide content renderer with per-breakpoint typography controls — the snippet this section calls for every slide. That page is about what renders inside a slide; this one is about the carousels around it.
- Accessible play/pause web component for autoplaying hero video — the control a video slide mounts, keyed by the same per-slide uid.
- Landing-page hero sections with a no-JS add-to-cart on page templates — the same problem on a different storefront and a different theme base, solved as a block-repeater with no carousel at all.
The Buy-vs-Build Question
A slider app buys a hero with its own editor and its own runtime. Building this one bought a hero in version control, art direction per breakpoint, and promotion events that read the merchandiser's own copy — and cost a section that renders its slide markup twice on every page view to get there. Whether that trade is yours is the question on the landing page builder decision page.
Provenance & Evidence
- Client: Nudestix — nudestix.com
- Surface: Home page
- Templates served: one — the
indextemplate - Complexity: High
- Attribution: Deploi-authored. The section, its block schema and its script are ours. It runs in a theme based on Dawn 6.0.2, and the carousels themselves run on Swiper, a third-party library the theme already loads.
- Status: Live, verified 2026-09-06
- Evidence: One section file from the theme, plus three specification documents and eight task-register entries from client working sessions
- Confidence: Strong — the code and the client record describe the same hero
- Primary capability: Art-directed hero and banner system
Ready to Ship a Campaign Hero Without Shipping Code?
You dream it. We build it. If every drop's hero still goes through a developer, Contact us today and we'll map which parts of yours could be settings instead.