Shopify Builds>Capabilities>Variant swatches and shade pickers

Variant Swatches and Shade Pickers on Shopify

Definition

Color-accurate swatch and pill pickers on product pages and product cards, driven by a merchandiser-managed hex registry or metafield rather than a swatch app. Covers duo-tone shades, finish grouping, size pills with merchandiser-named labels, and swatch filters on collection pages. Replaces one of the most commonly rented app categories with native theme code.

The Evidence

  • Evidence strength: 13 live, Deploi-attributed builds across 3 Shopify storefronts.
  • Split by storefront: Nudestix 8, Three Ships 3, LUS Brands 2.
  • Split by attribution: 8 Deploi-authored, 5 modifications of vendor theme code — named as such on each build page.
  • Evidence quality: six carry code plus client working records. Seven are documented from the code; no client-side record of the decision survives.
  • Confidence: 5 strong, 8 moderate.
  • Surfaces: product pages, collection and search grids, home rails, cart-side upsell cards.
  • Status: Live, verified 2026-09-06.

How It's Actually Built

Start with what a swatch is here, because it decides everything after it. In all 13 builds the swatch is Shopify's own variant radio input with a painted label on top of it. Nothing intercepts the product form and nothing holds a parallel selection state, so the picker inherits the theme's variant-change event, its price update and its media swap without being told any of them exist.

The color has to come from somewhere, and on a theme this old Shopify offers nowhere: Nudestix runs Dawn 6.0.2, which predates native swatch metaobjects on option values. So we made a place for it. settings.swatch_colors is one textarea holding roughly 250 Shade Name:#hex entries — one text field doing a database's job, and we know it.

A flat list doesn't survive a beauty catalog, so it carries two conventions. Name:#hex|Product Title scopes a hex to a single product, so the same shade word can be different pigment in two ranges. Name:#hexA&#hexB paints a duo shade as a hard-stop linear-gradient. Four surfaces read that one string — the PDP picker, the collection card, the kit modal and the cross-product selector — which is what keeps a single shade vocabulary everywhere a chip appears. Underneath sits a normalizer: product-get-options-strip-symbols.liquid strips 32 punctuation characters and downcases, so one key survives a CSS attribute selector, a data-value attribute and a JavaScript lookup.

Grouping is the second half of the pattern. Finish — Matte, Matte Lux, Bloom — is not an option dimension, because making it one would have multiplied the SKU matrix. It lives on variant.metafields.my_fields.stick-type, and the section pre-scans the variant list to decide whether to render one flat swatch row or one labelled fieldset per finish. Merchandising badges ride the same pass: custom.new_badge and custom.restocked render NEW and RESTOCKED pills, with an adjacency check on the neighbouring variants that fixes spacing when two badges land side by side.

The other two storefronts use the same primitive on a different problem. LUS Brands sells one formula in several sizes, so its picker is a pill rather than a chip: product-variant-options.liquid finds the first variant carrying an option value and reads variant.metafields.custom.option_custom_label, so a merchandiser writes "Travel" above "2.5 fl. oz" instead of leaving the shopper to infer it. Three Ships needs the choice on the grid, so one capture-phase click handler on document turns a card's size pills into a variant selection and posts the chosen id to /cart/add.js — capture phase specifically, because those cards are injected after load by carousels, upsell rails and section-rendered responses.

The Buy-vs-Build Position

The corpus's own verdict:

Built natively on all three storefronts.

That is a finding about three storefronts, not a ruling on the app category. Swatch apps are a reasonable purchase, and on a current theme Shopify's own option-value swatches cover the ordinary case for free — Three Ships' grid card reads option.swatch.image and option.swatch.color natively alongside the older approach. What pushed these three stores into theme code was narrower than "swatches": shade names reused across lines with different pigment, duo-tone shades needing two colors in one chip, finish grouping that is deliberately not an option, and a size pill that has to work inside a card that does not exist yet. Where that line sits is argued on the swatches and visual options decision page.

The Builds

Ten of the 13 have published pages. Two of the others — the cross-product shade and format selector and the four-mode filter UI — are documented and will follow. The third folds into a build page already published here.

Nudestix

Three Ships

LUS Brands

What This Rests On

  • Liquid section schema and settings — 12 of the 13 builds; every merchandiser control here is a section setting or a block.
  • Theme settings schema — where the shade registry lives, and why a new shade color is a merchandising action rather than a deploy.
  • Metafields — 9 builds; finish, size label, badge state, marketing color text, per-product grouping.
  • Custom elements — the variant-radios and selector components the swatch markup mounts inside.
  • Cart AJAX API — the grid and upsell pickers add in place rather than routing to the product page.
  • Storefront filtering and Section Rendering API — swatch facets, and the re-render they survive.
  • Metaobjects — the badge definition read for per-variant social proof.

What Varies by Storefront

Theme base decides how much of this is ours. LUS Brands runs Dawn 15.4.1, so its picker is Dawn's picker with two snippets slotted into the existing product-variant-options contract — data-option-value-id, data-product-url and the visually-hidden unavailable label all stay. Nudestix runs Dawn 6.0.2, nine major versions behind and older than native swatch support; that gap is why a color registry had to be invented in theme settings rather than read off the option value. Three Ships runs Palo Alto 5.8.0 by Presidio Creative, a paid premium theme, so the grid card is vendor code we extended and the edits are narrow and named on the build page.

Catalogue shape decides the rest, and it is the bigger factor. A shade-led cosmetics catalogue is a different swatch problem from a haircare catalogue, not a bigger one. In cosmetics the shade is the decision, shade names collide across lines, finish is a grouping axis nobody modelled as an option, and one product carries dozens of chips — so the work is disambiguation and grouping. In haircare the same formula ships in three sizes and the question is which size, not which color, so the same primitive renders as a labelled pill and the whole problem is a per-variant label lookup. Skincare sits between: the choice is size and format, but it has to happen on the grid card, so the interesting part moves out of Liquid and into event delegation. Each storefront also has a different set of things already bound to the product form and the card — reviews, wishlist, upsell rails — so the picker coexists with a different neighbour list on each.

Where This Gets Hard

A color registry is a database with no schema. Roughly 250 entries in a textarea, with two hand-parsed conventions layered on top, is a merchandising asset that needs a named owner on the client side — someone whose job includes adding the chip the day a shade launches. It is also a contract, not just a list: four surfaces read that one string, and every new surface that shows a chip is a fifth reader of it. Handing the color list to a merchandiser hands them something the rest of the storefront depends on.

The parsing cost lands in Liquid, on every render. The registry string is split once per product render and then walked per option value, so the work grows with shades multiplied by registry size. That is fine at this catalogue size, and it is a real number that gets bigger rather than a free abstraction.

The conventions carry their own coordination cost. | for product scoping and & for duo-tone are a private format that several snippets have to agree on, and the people who edit the registry are not the people who read the parser.

So there are cases where we would tell you not to build this. On a current theme with unique shade names, Shopify's native option-value swatches already do it, and a registry buys you parity plus a maintenance job. For a handful of colorways, a swatch app is cheaper than the argument about who owns the hex list. And if nobody on the merchandising side will own that list after launch, an app that stores the colors for you fails more gracefully than a registry going quietly stale.

Related Capabilities

Answers to Help You Make Smart Decisions

Do I need an app to add color swatches to a Shopify product page? Not usually. Current Shopify themes read a swatch directly off the option value, and a theme that predates that can paint the chip in Liquid from a merchandiser-managed color list. All 13 builds here render the swatch as the theme's own variant radio, so the picker keeps the theme's price, availability and media behaviour without a second script on the page.

Why paint swatches server-side instead of with JavaScript? Because a swatch painted in Liquid is in the first frame. A client-side swatch layer re-renders the picker after paint, which is where the color flash comes from, and it puts the color data outside Shopify. Rendering in Liquid also means the correct chip is in the initial HTML, so it is there for a crawler and there before any script runs.

How do you handle two products that use the same shade name for different colors? With a scoping convention in the color list. An entry written as Name:#hex|Product Title applies that hex only where the product title matches, so one flat registry can serve a catalogue that reuses shade words across ranges. It is the specific thing a name-to-hex map cannot do on its own, and the specific reason a bare map is not enough for beauty.

Can shoppers pick a variant without leaving the collection page? Yes. On one storefront here, size pills render inside the grid card and a delegated handler posts the chosen variant to the cart AJAX API. The rule that matters is in the code: add-to-cart is blocked until a size is selected, so an arbitrary default variant can never reach the cart.

Ready to Give Your Shades the Picker They Deserve?

If your product page hides half your range behind a dropdown, the problem isn't the range. Contact us today and we'll tell you whether your theme can paint the swatch natively — and what it would actually cost if it can't.

Builds

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

"Save With Sets": shade-selectable kit contents on the component product's page

A metafield-linked list of kits renders as an accordion on the product pages of the products inside them, and each kit opens a modal where every component gets its own shade picker before a single add-to-bag.

Nudestix

On-model shade carousel bound two ways to the Dawn variant picker

A Flickity carousel of one on-model shot per shade, rendered below the product gallery from a variant metafield; each cell carries the id of its Dawn variant radio, a tap on a face resolves to a click on that radio, a click on a radio moves the carousel — and the carousel itself never touches the product form.

Nudestix

Grouped shade swatch picker with shade-finder dialog and GA4 shade-finder events

Finish became a variant metafield instead of a second product option, which is what lets forty shades group into Matte, Matte Lux and Bloom without touching the SKU matrix — and the shade quiz beside them is bought, wrapped in a native dialog and measured on our side of the boundary.

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

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

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

Size-pill variant picker and quick add-to-cart inside product grids

One click handler, registered once on `document` in the capture phase, turns any grid card with a size-pill row into a variant selector and an add to cart — including cards that did not exist when the page loaded.

Three Ships

Inline size picker on cart and PDP upsell cards

Size pills added inside the premium theme's own upsell card, so a multi-variant upsell in the cart drawer, on the cart page or in a product-page "pair with" module can be sized and added where it stands instead of sending the shopper somewhere else.

Three Ships