Shopify Builds>Primitives>Custom elements

Custom elements

Definition

A custom element is a browser-native component: a class registered against a hyphenated tag name, with lifecycle callbacks that run when the tag enters or leaves the document. It needs no framework and no build step. Shopify's Dawn is written this way, so any theme descended from Dawn inherits the pattern along with the markup.

Documented at MDN, using custom elements.

How We've Used It

The lifecycle is why we use them, more than the encapsulation. Anything that arrives as fetched HTML, a filtered grid, a re-rendered drawer, a quick-view panel, has to bind itself, and an element that connects as it's parsed does that with no re-initialization call from whatever replaced the DOM. So variant pickers, swatch registries, media galleries, compare drawers and bundle builders are elements first and scripts second, and the ones that extend Dawn's own classes keep the vendor behavior for everything we didn't override. It keeps the contract visible in the markup too. A tag name says what owns that subtree, which matters on a page where three vendors also want it.

Builds Using It

8 further gated builds use it; their pages follow.

Related Entities

Builds

Alt-text driven variant media gallery with tiered matching and full-screen lightbox

The product gallery that consumes the alt-text match tiers: it builds the main slider, the thumbnail rail and a full-screen lightbox out of server-side verdicts, then re-filters the same nodes in the browser when the shopper changes variant.

LUS Brands

A collection template turned into a palette builder that carts one priced SKU

A pick-your-own palette promotion runs on a normal collection page wrapped in a `<bundle-element>` custom element, which holds a fixed tray of empty slots and posts one priced bundle product with the shopper's picks attached as line-item properties.

Nudestix

A second product template whose add-to-bag switches between one cart line and several

`main-product-bundle.liquid` is a fork of the theme's product section in which one Liquid conditional wraps the buy form in either a standard `<product-form>` or a `<bundle-product-form>`, depending on which bundle metafield the product carries.

Nudestix

Product-card hover video and a reusable deferred-media playback refactor

The shared product card's hover slot can hold a short clip instead of a second still: a per-product metafield decides which, the card emits a video that fetches nothing until asked, and a pointer-only, motion-aware binder plays it on hover of the whole card — plus a refactor of Dawn's deferred-media element that handles every player kind through one function.

LUS Brands

Collection grid card on a licensed theme: metafield merchandising, a badge precedence chain, a hover-swap swatch element and first-row loading hints

Palo Alto's grid item extended so the card's title, strapline, cutline and badge come from product metafields, badges resolve in one fixed order, color options become a swatch element that swaps the card image on hover, and column classes are computed from whatever section happens to be calling.

Three Ships

Curl Quiz 3.0: a nine-step diagnostic quiz rendered entirely from Shopify metaobjects

A nine-step hair diagnostic on the LUS Brands storefront whose questions, options and selection rules live in Shopify metaobjects rather than in the section's code. The theme editor exposes exactly one setting.

LUS Brands

Predictive search moved off Shopify onto an external search API with client-side templating

The type-ahead rebuilt from the inside: same custom element, same keyboard model, same ARIA contract — a different data source and a render step that did not exist before.

Nudestix

Kids featured collection: a custom element that builds its Swiper on approach and wraps the theme's own product cards

A `<kids-featured-collection>` element leaves its slides as static markup until an IntersectionObserver fires, initializes Swiper then, and tears everything down when the section is removed — around Dawn's `card-product`, not a card of its own.

LUS Brands

Dawn media gallery hardened for hidden slides and deferred video

A surgical patch to Dawn's `media-gallery` custom element so that selecting, reordering and announcing media all skip slides the server has hidden for the current variant — and so a variant with no matching thumbnail degrades to a sensible slide instead of an exception.

LUS Brands

Mega-menu header with separate mobile menu and image blocks

A second link-list setting gives the mobile drawer its own information architecture, and section blocks put imagery into panels that Shopify's link lists have no way to carry it in.

Three Ships

Tabbed mobile Shop menu with featured banner panel

A custom `<shop-tabs>` element turns the drawer's first-level Shop menu into horizontal tabs with panels of category links, merges a theme-editor banner block into the tab order by position, and leaves every other drawer item on the vendor's accordion.

Three Ships

Mobile sticky add-to-cart bar mirrored from the real product form

A bottom bar portaled to `<body>` that mirrors quantity, button label, disabled and loading state from the product page's own form, forwards taps into it, and follows iOS Safari's visual viewport as the browser chrome collapses.

LUS Brands

Rebuilt 2026 PDP section with merchandiser-composable blocks and per-product ATC color

A custom product section for LUS Brands that declares 26 block types beyond Dawn's set, resolves title and subtitle copy per variant, and paints the add-to-cart button from a product metafield.

LUS Brands

Side-by-side product comparison drawer and modal table

A compare-products flow with no app behind it: card checkboxes write the selection to localStorage, a drawer pinned to the bottom of the viewport carries it from collection to product page and back, and the modal table fetches each product's long-form copy from that product's own page section at the moment the shopper asks to compare.

Nudestix

Color-accurate shade swatches driven by a merchandiser-editable hex registry

Roughly 250 `Shade Name:#hex` pairs live in one theme setting. The product section resolves every option value against them in Liquid, groups the results by finish, and paints each swatch server-side.

Nudestix

Themed host section for Shopify Forms app blocks

A section whose only block type is `@app`, wrapping any app block in the theme's width, padding and background scaffolding — and, when a merchandiser switches it on, writing the `--forms-heading-*` and `--forms-body-*` custom properties that Shopify's Forms embed reads for its own typography.

Three Ships

Subscription bundle grid with tiered unlock progress

Two custom elements on the subscription landing page: a card whose two-step button reveals a frequency choice and then posts the variant with that `selling_plan` to the cart, and a wrapper that fetches the live cart after every add and drives a merchandiser-defined tier bar from what it finds there.

Three Ships

Shade swatch rendering and per-variant content payload

The swatches are the visible half. The other half is a hidden input per variant carrying that shade's copy, ingredients, SEO fields and badges — a data contract three separate features read without asking the server anything.

Nudestix

Pill variant picker with merchandiser-named size labels

Dawn prints an option value and nothing else. We extended its picker so a size pill carries two lines — a merchandiser's word for that size above the size itself — and falls back to positional defaults when nobody has written one.

LUS Brands

Vertical filter rail and an in-place mobile filter accordion replacing Dawn's drill-down drawer

Dawn's facets snippet was rebuilt into a sidebar rail with color swatches and show-more truncation, an accordion mobile drawer where every group opens in place, and a single sort control that physically relocates between breakpoints.

LUS Brands

Responsive video hero with independent desktop/mobile sources and single-source-of-truth playback controls

A `<video-hero>` custom element that holds a 16:9 cut and a 9:16 cut, promotes only the active breakpoint's sources to `src`, and wires one play/pause and one mute button to whichever video is live — with server-rendered control state so the buttons read correctly before the script runs.

LUS Brands

Accessible play/pause web component for autoplaying hero video

A `<play-pause>` custom element that gives a muted, autoplaying hero video a real keyboard-reachable control — self-wiring from a selector in its own markup, so Swiper can clone and reorder slides without any script knowing how many there are.

Nudestix