Skip to main content

Migrate EmptyState 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 ReactPolaris web componentsMigration type
EmptyStates-empty-stateDirect

Polaris ReactPolaris web componentsMigration notes
headingheadingPass the plain-text heading directly. Move inline markup into the subheading slot.
childrensubheading slot with s-text and s-linkReplace nested paragraphs or layout wrappers with the supported slot children.
actions-button in the primary-action slotUse variant="primary" and map the action's URL, click handler, loading, and disabled state.
secondaryActions-button in the secondary-actions slotUse variant="secondary" or variant="auto". The slot accepts one button despite its plural name.
image and largeImages-icon or a constrained s-image in the graphic slotPrefer 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 fullWidthRemoves-empty-state owns its graphic and content layout. Don't recreate these sizing modes with internal selectors.
footerContentMove into subheading, an action slot, or adjacent contentUse 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

  1. Keep the existing condition that distinguishes loading, empty, populated, and error states. Outside a table, render s-empty-state only when the resource is empty.

  2. Move the heading and supporting copy into heading and subheading, then place at most one correctly styled button in each action slot.

  3. Move the old illustration into the graphic slot, or remove it if the heading and action communicate the state without it.

  4. After verification, remove the EmptyState import 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.


Migrating EmptyState

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>
);
}
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>
);
}

Preview


Was this page helpful?