Shopify Builds>Capabilities>Design system and reusable component library

Design Systems and Component Libraries on Shopify

Definition

The shared vocabulary underneath the sections: documented Liquid authoring snippets that own their own CSS, design tokens emitted per instance as custom properties and consumed by a static stylesheet, inline SVG icon libraries addressed by name with unique internal ids, pagination and scroll-snap primitives that need no library, borrowed vendor behavior contracts, and contrast fallbacks that stop merchandisers shipping an invisible button.

The Evidence

  • Evidence strength: 31 live, Deploi-attributed builds across 3 Shopify storefronts.
  • Split by storefront: LUS Brands 13, Three Ships 10, Nudestix 8.
  • Split by attribution: 25 Deploi-authored, 6 modifications of vendor theme code — named as such on each build page.
  • Evidence quality: fifteen carry code plus client working records. Sixteen are documented from the code; no client-side record of the decision survives.
  • Confidence: 14 strong, 17 moderate.
  • Surfaces: everywhere, which is the point — landing pages, home, collection and product pages, plus the global header, footer and cart.
  • Status: Live, verified 2026-09-06.

This is the most evenly distributed capability in the section, because every storefront eventually needs a second developer to write the same button the same way.

How It's Actually Built

Shopify gives you two places to put design decisions and nothing in between. settings_schema.json holds global theme settings; a section's schema holds per-instance settings. There is no layer that survives a section boundary — no import, no package, no compile step that fails when someone reinvents the button. So a design system here is built out of conventions, and the conventions are the system.

Tokens, emitted per instance, consumed by a static stylesheet. A scoped {% style %} block loops section.blocks and writes CSS custom properties keyed to block.id--rt-btn-bg, --rt-btn-radius and their hover triples for buttons; --kiwt-h-size and --kiwt-h-size-md for a heading's mobile and desktop scale; --highlight-color for the accent. The compiled stylesheet owns the layout and reads the tokens, so the generated CSS is only ever the per-instance values. Pixel settings are divided by ten into rem on the way through, so a merchandiser typing a number still lands on the theme's root scale, and a custom max-width is clamped in Liquid against settings.page_width.

Documented snippets that own their own CSS. button-link.liquid renders an anchor with a per-instance scoped class and ships a {% stylesheet %} block driving every visual property from those custom properties, so the styles are collected only when the snippet is used and there is exactly one file to change. highlight-text.liquid implements a [[word]] convention: it splits merchandiser copy on the delimiters and wraps the inner run in a span. That exists because Shopify's inline rich-text setting gives you bold and italic but no way to color one word in the brand accent — and because the alternative, letting people paste HTML into a heading, is a surface nobody wants. Both carry {% doc %} blocks with typed @param and @example.

Icons as inline SVG snippets, not a font and not a sprite. Replacement glyphs keep the vendor theme's own snippet-name contract, so the cart icon could be swapped without editing the header, the bubble or the drawer, and currentColor is set on both fill and stroke so one file works on a light ground and an inverted one. New brand marks are added as standalone snippets rendered by the custom sections rather than into the vendor's {% case %} dispatcher — that keeps the vendor's icon list intact for the vendor sections that expose it as a merchandiser select, and keeps the addition out of a file the next theme update will overwrite. Where the same generated SVG appears twice on one page, every internal mask and pattern id and every url(#…) reference takes an id_suffix argument, because browsers resolve url(#id) to the first match. The suffix comes from block.id rather than a loop index, so it stays stable when merchandisers reorder blocks.

Primitives that cost nothing to run. A logo row becomes a carousel with no library at all: grid-auto-flow: column, columns sized from a --columns custom property, overflow-x: scroll with scroll-snap-type: x mandatory, scroll-snap-align: start and scroll-snap-stop: always, and a deliberate peek of the next tile as the affordance. Where a component genuinely needs script, it is a self-registering custom element: define() guarded by customElements.get so a double include is a no-op, binding in connectedCallback so markup injected later still wires up, and disconnectedCallback removing every listener so a theme-editor re-render does not leak handlers.

Borrowed behavior contracts. The clearest example is a product-page accordion that reuses the premium theme's own data-collapsible-trigger, -container and -content attributes while supplying its own markup and CSS-variable styling. One accordion behavior on the page, one visual treatment that is nothing like the vendor's. Contrast is guarded the same way: a shared card renderer measures color_brightness on the merchandiser's chosen background and derives the button hover color from it rather than trusting a second color picker, and when overlay opacity is at maximum it skips the image and draws a flat block.

The Buy-vs-Build Position

The corpus's own verdict:

Built in every engagement and reused across hundreds of section placements — the substrate that makes the other build decisions cheap.

The honest counterweight is that a premium theme often ships a token layer already, and a good one is work you do not have to do. Palo Alto generates its whole design system inside one snippet rendered in <head> by every layout: weight-ladder resolution for base, heading, subheading, nav and label fonts, a color ramp derived with color_lighten, color_darken and color_modify, and layout tokens for gutter, grid, drawer width and swatch size. Where that exists, this capability is extension rather than authorship — six of the 31 builds are deploi-modified-vendor for exactly that reason. Where the theme is Dawn, the token layer is the thing you write. Our fuller reasoning is on the theme section library and design system decision page.

The Builds

Nine of the 31 have published pages, and the published subset skews to one storefront — the evidence split above is the real distribution. Of the rest, eighteen — the authoring-primitive snippets, the icon sets and the token layers among them — are documented and will follow. Four won't get pages of their own: three fold into build pages already published here, and editorial review didn't clear the fourth.

LUS Brands

Nudestix

Three Ships

What This Rests On

  • Liquid section schema and settings — 25 of the 31 builds. Settings are the design system's public interface, for better and worse.
  • Theme blocks — 9 builds; the scope a per-block token rule is keyed to.
  • CSS custom properties — the actual token carrier, and the reason one static stylesheet can serve every configuration.
  • Metafields — where a component's content lives when a setting would be wrong, such as a per-product override.
  • Custom elements — the self-registering, self-cleaning unit every scripted component here is built as.
  • Liquid snippets — the closest thing Shopify has to a component, with {% doc %} and {% stylesheet %} doing the rest.
  • Section Rendering API and local storage — how the comparison component fetches the copy it needs once and keeps a selection across navigation.
  • Theme settings — the global half of the token story, including a vendor theme's generated ramp.

What Varies by Storefront

The platform version decides the shape of the system more than taste does. LUS Brands runs Dawn 15.4.1, where theme blocks exist and snippets can carry {% doc %} and {% stylesheet %} — so the system there is snippet-shaped: documented authoring primitives that several sections render, each theming them through custom properties rather than a growing argument list. Nudestix runs Dawn 6.0.2, nine major versions older, with no theme blocks and no per-block CSS scoping — so the same job is done by section-level {% style %} output and snippets parameterised with a key so several instances coexist on one page, and the reusable layer leans harder on JavaScript.

Three Ships runs Palo Alto 5.8.0 by Presidio Creative, a paid premium theme, and the difference there is authorship rather than technique. The token generator, the icon dispatcher and the collapsible behavior are all vendor code; the local work sits at the edges — brand webfonts appended to the generated token block, brand marks added beside the dispatcher rather than inside it, and components that adopt the vendor's behavior contract so the page keeps one of everything. That is why six of these builds are attributed as modifications, and why the ones that are say so on their own pages.

Where This Gets Hard

A snippet is not a package. There is no version, and no way to ship a second copy of a component while its callers migrate — so a breaking change to a shared button or a shared text helper is a same-day, all-callers change. {% doc %} and {% stylesheet %} genuinely help: they document the contract and scope the CSS. What they cannot give you is a migration path.

The harder problem is adoption, and it is not technical. A component library pays off only when the next section uses it, and nothing in Shopify makes that happen: no linter fails, no build breaks, no reviewer is forced to notice that someone wrote the button again with inline styles because it was faster that afternoon. The discipline is a code-review habit, which makes the value of this capability a staffing decision wearing engineering clothes.

And the interface is the theme editor, which has no type system worth the name. A color picker is constrained; a spacing value, a class hook and a font name are free text. That is a real ceiling on how much of a design system you can safely delegate: the further you push token control toward merchandisers, the more of it is a value somebody typed.

So there are storefronts we would tell not to build this. One brand, one theme, a dozen custom sections: write the CSS — a token convention is overhead you will never amortise. If you bought a premium theme whose token layer already fits your brand, extend it and stop; a second vocabulary next to the vendor's gives you two systems that have to agree, and the person who notices they have drifted is a customer. And if nobody will own the convention after launch, a component library is a folder of files nobody calls.

Related Capabilities

Answers to Help You Make Smart Decisions

Can you have a real design system in a Shopify theme? Yes, but not as a package. It is a convention: tokens emitted as CSS custom properties from block settings, a small set of documented snippets that carry their own stylesheets, and a rule about which behaviors you borrow from the theme instead of rewriting. Shopify enforces none of it, which is why the convention has to be written down where developers read it.

Should design tokens be theme settings or section settings? Both, and the split matters. Global settings hold what must never diverge — the type ramp, the brand palette, the grid. Section and block settings hold the per-instance overrides a campaign genuinely needs. The failure mode is putting a global decision in a block setting, where it becomes a value somebody re-types on every placement.

What is the right way to handle icons in a Shopify theme? Inline SVG snippets rendered by name, with currentColor on fill and stroke so one file works on any ground. Two details matter: keep the vendor theme's snippet-name contract so an icon can be swapped without editing its call sites, and suffix internal SVG ids per instance, because browsers resolve a url(#id) reference to the first match on the page.

Is a premium theme's design system enough? Often, and if it fits your brand you should use it and stop. A good premium theme generates fonts, a color ramp and layout tokens from theme settings. The work starts when your brand needs something outside that vocabulary — and then the honest move is to extend the vendor's layer at its edges rather than stand a second one beside it.

Ready to Stop Writing the Same Button Twice?

If two developers on your theme would style the same component two different ways, you don't have a design system — you have a stylesheet and a memory. Contact us today and we'll tell you which parts of yours to name first.

Builds

Arched-label icon grid PDP block

A six-slot row of circular badge icons with captions that curve over them — an SVG `textPath` per label, an arc id composed from `block.id` so the block can repeat, and layout driven entirely by custom properties the merchandiser sets.

LUS Brands

Marketing image banner with mobile art, typography controls and highlight headings

A campaign banner built as a fork of Dawn's image banner: the vendor's class contract and overlay behaviour left intact, with a real mobile source, per-block type controls and an inline highlight convention layered on top.

LUS Brands

Press / trust logo strip with scroll-snap carousel and no JavaScript

A blocks-based logo row for the homepage that a merchandiser can reorder, relabel and link — and that becomes a swipeable, snapping carousel on mobile through CSS alone, with no slider library and no script of its own.

LUS Brands

Rich-text section rebuilt as a per-block typography and highlight system

Dawn's `rich-text.liquid`, kept under its own name and rebuilt inside: every heading, text and button block writes its own type, spacing and colour tokens as CSS custom properties, and the `[[word]]` highlight and the button become snippets other sections share.

LUS Brands

Variant-aware price snippet with percentage + value savings badge

Dawn's price snippet extended so a caller can hand it any variant object ahead of the snippet's own lookup, and so a savings badge — a percentage computed in Liquid plus a merchandiser-written value sentence — renders whenever the compare-at price is higher than the price.

LUS Brands

Accessible link-label helpers for repeated CTAs

Two Liquid snippets that resolve a real conflict between two link-naming rules — identical link text on different destinations versus an accessible name that must contain the visible label — by deriving a name from the link's href and emitting it only when it differs from what the shopper can see.

Nudestix

Hero slide content renderer with per-breakpoint typography controls

One Liquid snippet renders a hero slide's pretitle, title, description and CTA from block settings, carrying the desktop and the mobile type spec on the same element as paired CSS custom properties, so two different slideshow sections share a single copy renderer.

Nudestix

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

PDP content accordion that borrows the premium theme's collapsible contract

A product-page accordion block that reuses Palo Alto's own `data-collapsible-*` behavior wiring while supplying its own heading semantics, CSS-variable theming and a responsive table layout for the long-form panels merchandisers author per product.

Three Ships