---
title: Migrate EmptyState from Polaris React
description: Learn how to migrate Polaris React EmptyState to Polaris web components.
source_url:
  html: >-
    https://shopify.dev/docs/apps/build/app-home/migrate-from-polaris-react/empty-state
  md: >-
    https://shopify.dev/docs/apps/build/app-home/migrate-from-polaris-react/empty-state.md
api_name: app-home
---

# 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](https://shopify.dev/docs/api/app-home/v1.1/web-components/versioning) 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.

***

## Choose the destination

| Polaris React | Polaris web components | Migration type |
| - | - | - |
| `EmptyState` | [`s-empty-state`](https://shopify.dev/docs/api/app-home/v1.1/web-components/feedback-and-status-indicators/empty-state) | Direct |

***

## Map 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. |

***

## Migrate 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.

***

## Preserve 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.

***

## Test 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.

***

## Migration example

## Migrating EmptyState

##### Polaris web components

```tsx
// @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

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

***
