Skip to content
Back

Checkout Polaris

The component library and web components powering checkout extensions for millions of Shopify merchants.

Apr 2026 · 3 min read · shopify.dev

Checkout Polaris is the design system that powers the checkout surface across every Shopify storefront — and the public surface third-party developers use to extend it with Checkout UI Extensions.

For most of its life, the library was a React-only API. The 2026-07 release candidate flips that: components ship as framework-agnostic web components, while the React API becomes a thin wrapper that returns the same custom elements.

Why web components

Three reasons drove the rewrite, in order of how often I had to defend them:

  1. Sandboxed by default. Extensions run inside a worker, with no access to the host page's React tree. Web components are the smallest interop surface that survives that boundary — a <s-button> rendered in the worker hydrates as a real <s-button> in the host without any framework coupling.
  2. Bundle size. Pre-Polaris extensions shipped a copy of React per extension. Pulling that out means cold-load time drops measurably on the slowest mobile connections — the only place it actually matters for checkout.
  3. API stability. Custom elements give us a versioned tag name (<s-button-v1>) without needing a new npm package per breaking change. Merchants don't see the version; extension authors opt in by tag.

The interesting move is sideways: the React layer didn't disappear, it just stopped being load-bearing.

What it looks like

// Before — React-only
import { Button, BlockStack } from "@shopify/ui-extensions-react/checkout";

export default reactExtension("purchase.checkout.block.render", () => (
  <BlockStack>
    <Button>Checkout</Button>
  </BlockStack>
));
<!-- After — same thing, web components -->
<s-block-stack>
  <s-button>Checkout</s-button>
</s-block-stack>

The React import still works; it just compiles down to the second snippet. Extension authors using Vue, Svelte, or vanilla JS can now build first-class extensions without us shipping framework-specific bindings.

The parts I worked on

I spent six years on the team that owns this surface. The pieces I'm proudest of:

Where to read the real docs

This post is a brief, opinionated tour. The real documentation lives at:

If you're building an extension and want a second opinion on shape or accessibility, you know where to find me.