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
Polaris web components
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>
);
}Polaris React
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
Anchor to Map the page headerMap the page header
| Polaris React prop | Replacement | How to migrate |
|---|---|---|
title | heading | Keep one concise heading that identifies the route or resource. |
backAction | s-link | Set slot="breadcrumb-actions", move url to href, and use the parent page name as visible text. |
primaryAction | s-button | Set slot="primary-action" and variant="primary". Reconnect loading, disabled, and click behavior. |
secondaryActions | s-button or s-button-group | Put frequent actions in slot="secondary-actions". Use one slotted trigger and an unslotted s-menu for overflow actions. |
actionGroups | s-button and s-menu | Add a slotted trigger for each necessary group. Keep its menu unslotted, and remove groups that duplicate page content or navigation. |
titleMetadata | Omit from the page shell | s-page doesn't have an accessory slot. Add status to page content only when it provides necessary information there. |
subtitle and additionalMetadata | Introductory content in the page body | Use semantic paragraphs, badges, or links in the relevant section. |
pagination | s-table pagination or an in-content pagination composition | Keep pagination with the data it controls rather than in the title bar. |
titleHidden | A visible heading in most routes | Don't remove the page's only heading. If the design genuinely needs no title bar, preserve an accessible content heading. |
pageReadyAccessibilityLabel | Route-level announcement and focus behavior | Announce 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 React | Polaris web components | Migration notes |
|---|---|---|
| Default width | inlineSize="base" or omit the property | Use for most pages. |
narrowWidth | inlineSize="small" | Use for focused, single-column tasks. |
fullWidth | inlineSize="large" | Use only when the content benefits from the available width, such as a dense data view. |
| Layout sidebar | slot="aside" | The aside renders only with inlineSize="base". Keep primary task content in the default slot. |
children | Default page content | Compose 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.
Anchor to Test the migrationTest the migration
- 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.
- Page component
- Migrate Breadcrumbs from Polaris React
- Migrate PageActions from Polaris React
- Migrate Layout from Polaris React