Migrate Empty State from Polaris React
Replace Polaris React EmptyState with s-empty-state. Map the heading, supporting text, graphic, and actions into the component's named slots, and keep app-owned empty-state detection outside the component.
s-empty-state is available in Polaris 1.1 and later. The stable channel, polaris-1.js, includes it; install @shopify/polaris-types@^1.1.0 alongside it. If you pin polaris-1.1.js instead, use @shopify/polaris-types@~1.1.0 so the types stay on 1.1 like the script tag.
Anchor to Choose the destinationChoose the destination
| Polaris React | Polaris web components | Migration type |
|---|---|---|
EmptyState | s-empty-state | Direct |
Anchor to Map the empty stateMap the empty state
| Polaris React | Polaris web components | Migration notes |
|---|---|---|
heading | heading | Pass the plain-text heading directly. Move inline markup into the subheading slot. |
children | subheading slot with s-text and s-link | Replace nested paragraphs or layout wrappers with the supported slot children. |
action | s-button in the primary-action slot | Use variant="primary" and map the action's URL, click handler, loading, and disabled state. |
secondaryAction | s-button in the secondary-actions slot | Use variant="secondary" or variant="auto". The slot accepts one button despite its plural name. |
image and largeImage | s-icon or a constrained s-image in the graphic slot | Prefer a compact icon when it communicates the empty resource type, as in the example. For an illustration, constrain it to the intended graphic size and use srcSet and sizes when separate sources are still necessary. Polaris React treated these illustrations as decorative, so preserve alt="" and accessibilityRole="presentation" unless the content requirements have changed. |
imageContained and fullWidth | Remove | s-empty-state owns its graphic and content layout. Don't recreate these sizing modes with internal selectors. |
footerContent | Move into subheading, an action slot, or adjacent content | Use the slot that matches its purpose. Put unrelated controls or information after the empty state instead of forcing them into an unsupported slot. |
Anchor to Migrate the call siteMigrate the call site
-
Keep the existing condition that distinguishes loading, empty, populated, and error states. Outside a table, render
s-empty-stateonly when the resource is empty. -
Move the heading and supporting copy into
headingandsubheading, then place at most one correctly styled button in each action slot. -
Move the old illustration into the
graphicslot, or remove it if the heading and action communicate the state without it. -
After verification, remove the
EmptyStateimport and any Polaris-only state, wrappers, or helpers that no longer have a caller.
Anchor to Preserve these behaviorsPreserve these behaviors
- The condition that chooses the empty state instead of loading, populated, or error content.
- Navigation, loading, disabled, success, and error behavior for both actions.
- Decorative image semantics and responsive behavior in narrow containers.
Anchor to Test and remove Polaris ReactTest and remove Polaris React
Test the populated-to-empty transition and both action outcomes. Verify that unsupported slot children produce no console warnings, the graphic remains decorative, and the empty state doesn't render during loading or error states.
Don't remove @shopify/polaris while another component still imports it. Once all call sites are migrated, remove the package and its provider-level setup, then run the app's full test suite.
Anchor to Migration exampleMigration example
Migrating EmptyState
Polaris web components
// @validate-ignore: Property 's-empty-state' does not exist on type 'JSX.IntrinsicElements'
export function EmptyStateMigrationExample() {
return (
<s-empty-state heading="Add your first product">
<s-icon slot="graphic" type="product" />
<s-text slot="subheading">
Products you add here are ready to sell across your sales channels.
</s-text>
<s-button
slot="secondary-actions"
variant="secondary"
href="/app/products/import"
>
Import products
</s-button>
<s-button
slot="primary-action"
variant="primary"
href="/app/products/new"
>
Add product
</s-button>
</s-empty-state>
);
}Polaris React
import {EmptyState} from '@shopify/polaris';
export function EmptyStateMigrationExample() {
return (
<EmptyState
heading="Add your first product"
action={{content: 'Add product', url: '/app/products/new'}}
secondaryAction={{content: 'Import products', url: '/app/products/import'}}
image="https://cdn.shopify.com/static/sample-product/House-Plant1.png"
>
<p>Products you add here are ready to sell across your sales channels.</p>
</EmptyState>
);
}