Skip to content

UI: Polaris & App Bridge ​

Embedded apps should look and behave like part of Shopify Admin. Two libraries make that happen.

LibraryWhat it is
App BridgeLoaded from Shopify's CDN. Connects your iframe to the Admin: title bar, nav menu, toasts, modals, resource pickers, and session tokens
Polaris web componentsShopify's design system as <s-*> custom elements. Matches the Admin look automatically

Polaris React is deprecated

The old @shopify/polaris React library is deprecated, and its components will be removed in future majors. New work should use Polaris web components (<s-page>, <s-section>, <s-button>…).

A page with Polaris web components ​

tsx
export default function Index() {
  const { orders } = useLoaderData<typeof loader>();
  return (
    <s-page heading="Recent orders">
      <s-button slot="primary-action" onClick={sync}>Sync now</s-button>

      <s-section heading="Last 10 orders">
        <s-table>
          <s-table-header-row>
            <s-table-header>Order</s-table-header>
            <s-table-header>Customer</s-table-header>
            <s-table-header>Total</s-table-header>
          </s-table-header-row>
          <s-table-body>
            {orders.map((o) => (
              <s-table-row key={o.id}>
                <s-table-cell>{o.name}</s-table-cell>
                <s-table-cell>{o.customer?.displayName}</s-table-cell>
                <s-table-cell>{o.total}</s-table-cell>
              </s-table-row>
            ))}
          </s-table-body>
        </s-table>
      </s-section>
    </s-page>
  );
}

Migrating from Polaris React — the gotchas ​

  • There is no Card. Use <s-section>.
  • Multi-word props become camelCase attributes, and url becomes href.
  • Migrate a whole page shell at once. Don't mix the two systems on one page.

App Bridge APIs you'll use ​

ts
shopify.toast.show("Saved");                          // toast
await shopify.resourcePicker({ type: "product" });   // native product picker
shopify.modal.show("my-modal");                      // <ui-modal id="my-modal">
const token = await shopify.idToken();               // session token (rarely needed by hand)

Navigation menu, in app.tsx:

tsx
<s-app-nav>
  <s-link href="/app" rel="home">Home</s-link>
  <s-link href="/app/settings">Settings</s-link>
</s-app-nav>

Built for Shopify checks this

The badge needs the latest App Bridge. It also needs fast Admin Web Vitals: LCP ≤ 2.5 s, CLS ≤ 0.1, INP ≤ 200 ms at p75. Keep loaders lean.

Project step: render the orders from the API page in an <s-table>, with a "Sync now" primary action that shows a toast.

Check yourself ​

  1. Which library gives you the session token?
  2. What replaces Polaris React's Card?