Skip to main content

Migrate Page from Polaris React

Replace Polaris React Page with s-page. Migrate the page shell as one unit so the heading, hierarchy, actions, width, and route content remain coherent in the Shopify admin title bar.


Anchor to Migrate a page shellMigrate a page shell

The destination uses supported page slots for breadcrumbs and actions. Omit content that doesn't have a title-bar slot, such as titleMetadata, from the page shell. Reintroduce it in page content only when it provides necessary information there.

Migrating a products page

export function ProductsPage({
onCreateProduct,
onDuplicateProduct,
onArchiveProduct,
}) {
return (
<s-page heading="Products">
<s-link slot="breadcrumb-actions" href="/app">
Home
</s-link>
<s-button
slot="primary-action"
variant="primary"
onClick={onCreateProduct}
>
Create product
</s-button>
<s-button slot="secondary-actions" onClick={onDuplicateProduct}>
Duplicate product
</s-button>
<s-button slot="secondary-actions" onClick={onArchiveProduct}>
Archive product
</s-button>
<s-section heading="All products">
<s-stack gap="small">
<s-paragraph>
Manage the products available through your app.
</s-paragraph>
</s-stack>
</s-section>
</s-page>
);
}
import {Badge, Card, Page, Text} from '@shopify/polaris';

export function ProductsPage({onCreate, onDuplicate, onArchive}) {
return (
<Page
title="Products"
backAction={{content: 'Home', url: '/app'}}
titleMetadata={<Badge tone="success">Active</Badge>}
primaryAction={{content: 'Create product', onAction: onCreate}}
secondaryActions={[
{content: 'Duplicate product', onAction: onDuplicate},
{content: 'Archive product', onAction: onArchive},
]}
>
<Card>
<Text as="h2" variant="headingSm">All products</Text>
<Text as="p">Manage the products available through your app.</Text>
</Card>
</Page>
);
}

Preview


Polaris React propReplacementHow to migrate
titleheadingKeep one concise heading that identifies the route or resource.
backActions-linkSet slot="breadcrumb-actions", move url to href, and use the parent page name as visible text.
primaryActions-buttonSet slot="primary-action" and variant="primary". Reconnect loading, disabled, and click behavior.
secondaryActionss-button or s-button-groupPut frequent actions in slot="secondary-actions". Use one slotted trigger and an unslotted s-menu for overflow actions.
actionGroupss-button and s-menuAdd a slotted trigger for each necessary group. Keep its menu unslotted, and remove groups that duplicate page content or navigation.
titleMetadataOmit from the page shells-page doesn't have an accessory slot. Add status to page content only when it provides necessary information there.
subtitle and additionalMetadataIntroductory content in the page bodyUse semantic paragraphs, badges, or links in the relevant section.
paginations-table pagination or an in-content pagination compositionKeep pagination with the data it controls rather than in the title bar.
titleHiddenA visible heading in most routesDon't remove the page's only heading. If the design genuinely needs no title bar, preserve an accessible content heading.
pageReadyAccessibilityLabelRoute-level announcement and focus behaviorAnnounce the loaded route through the router or loading pattern instead of passing a page-only compatibility prop.

The breadcrumb-actions slot accepts links. The primary-action slot accepts one primary button. The secondary-actions slot accepts buttons or a button group with secondary or automatic variants.


Anchor to Map page width and regionsMap page width and regions

Polaris ReactPolaris web componentsMigration notes
Default widthinlineSize="base" or omit the propertyUse for most pages.
narrowWidthinlineSize="small"Use for focused, single-column tasks.
fullWidthinlineSize="large"Use only when the content benefits from the available width, such as a dense data view.
Layout sidebarslot="aside"The aside renders only with inlineSize="base". Keep primary task content in the default slot.
childrenDefault page contentCompose sections, stacks, grids, and documented patterns from the information hierarchy.

Don't replace every Polaris React Card with another visual wrapper. Use s-section for a standard page region and a documented pattern when the old card represented a complete task.


Anchor to Keep route behavior intactKeep route behavior intact

Keep s-page at the route level instead of wrapping reusable leaf components in their own page. Update its heading and actions from the active route, and remove stale actions when navigating. Verify direct loads, browser back and forward navigation, and focus after the route finishes loading.

If the page contains unsaved form state, migrate its save bar and navigation protection before removing the Polaris React page shell.


  • Load the route directly and through app navigation, then verify the heading and breadcrumbs.
  • Run primary, secondary, overflow, disabled, loading, success, and failure action paths.
  • Test small, base, and large widths only where the route uses them.
  • Verify the aside doesn't contain primary task controls and behaves correctly at narrow widths.
  • Confirm browser history and route changes don't leave stale title-bar actions.
  • Verify heading order, link behavior, action names, and keyboard focus.

Anchor to Remove Polaris ReactRemove Polaris React

After every call site is migrated, remove Page, action descriptor builders, and CSS that targets Polaris page internals. Remove @shopify/polaris only after no other route in scope imports it.



Was this page helpful?