---
title: Migrate Toast from Polaris React
description: >-
  Replace the Polaris React Toast component and its render state with the App
  Bridge Toast API.
source_url:
  html: >-
    https://shopify.dev/docs/apps/build/app-home/migrate-from-polaris-react/toast
  md: >-
    https://shopify.dev/docs/apps/build/app-home/migrate-from-polaris-react/toast.md
api_name: app-home
---

# Migrate Toast from Polaris React

The [Toast API](https://shopify.dev/docs/api/app-home/apis/user-interface-and-interactions/toast-api) replaces the Polaris React `Toast` component. Both display brief, non-blocking feedback, but the Toast API is imperative: call `shopify.toast.show()` when an operation finishes instead of rendering a component from state.

***

## Migrate a toast

The following example removes the `Toast` component, the state that controls whether it is mounted, and the `Frame` that hosts it. The success and error messages move into the operation that produces each result.

## Migrating a save notification

##### Polaris web components

```tsx
function SaveProduct({onSave}: {onSave: () => Promise<void>}) {
  async function handleSave() {
    try {
      await onSave();
      shopify.toast.show('Product saved', {duration: 5000});
    } catch {
      shopify.toast.show("Product couldn't be saved", {isError: true});
    }
  }

  return <s-button onClick={handleSave}>Save product</s-button>;
}
```

##### Polaris React

```tsx
import {Button, Frame, Toast} from '@shopify/polaris';
import {useState} from 'react';

export function SaveProduct({onSave}: {onSave: () => Promise<void>}) {
  const [toast, setToast] = useState<{
    content: string;
    error?: boolean;
  } | null>(null);

  async function handleSave() {
    try {
      await onSave();
      setToast({content: 'Product saved'});
    } catch {
      setToast({content: "Product couldn't be saved", error: true});
    }
  }

  return (
    <Frame>
      <Button onClick={handleSave}>Save product</Button>
      {toast && (
        <Toast
          content={toast.content}
          duration={5000}
          error={toast.error}
          onDismiss={() => setToast(null)}
        />
      )}
    </Frame>
  );
}
```

***

## Updated properties

Map the properties used at each call site to the options passed to `shopify.toast.show()`.

| Polaris React | Toast API | Migration notes |
| - | - | - |
| `content` | First argument to `shopify.toast.show()` | Pass the message as a string. |
| `duration` | `duration` | The value remains a duration in milliseconds. |
| `error` | `isError` | Rename the option. |
| `action.content` | `action` | Pass the action label as a string. |
| `action.onAction` | `onAction` | Move the callback to the toast options. |
| `onDismiss` | `onDismiss` | The Toast API callback runs when the user clicks the dismiss control. Don't use it to detect expiry after `duration`. |

For example, migrate an undo action from a Polaris React action descriptor:

## Migrating a toast action

##### Polaris web components

```tsx
shopify.toast.show('Product archived', {
  action: 'Undo',
  onAction: restoreProduct,
  onDismiss: dismissToast,
});
```

##### Polaris React

```tsx
<Toast
  content="Product archived"
  action={{
    content: 'Undo',
    onAction: restoreProduct,
  }}
  onDismiss={dismissToast}
/>
```

***

## Removed state and hosting

### Render state

Remove state used only to mount and unmount `Toast`, such as `active` or a nullable toast descriptor. Call `shopify.toast.show()` from the success or failure path instead.

Keep state that belongs to the underlying operation. For example, a Save button might still need loading state while the request is in progress.

### Frame

`Toast` required a Polaris React `Frame` ancestor. The Toast API renders the notification in the Shopify admin, so it doesn't need an in-iframe host. Remove `Frame` only after migrating its other consumers, including navigation, loading indicators, and contextual save bars.

### Explicit dismissal

To hide a toast before its duration elapses, store the ID returned by `shopify.toast.show()` and pass it to `shopify.toast.hide(id)`. Most confirmation toasts should expire on their own.

***

## Preserve actionable errors

A toast is temporary. When an error requires the user to change a field, retry an operation, or refer to details, keep that error visible in the relevant form or page. You can also show an error toast as immediate feedback, but it shouldn't be the only place the recovery instructions appear.

***

## Test the migration

* Verify the success, error, action, and manual-dismiss paths used by the app.
* Confirm that repeated actions don't leave stale toast state in the React tree.
* Confirm that route changes and component unmounts don't suppress operation results that should still be shown.
* Test inside the Shopify admin, where the host renders the toast.

***

## Remove Polaris React

After every `Toast` call site is migrated, remove the `Toast` import and state used only to render it. Remove `Frame` separately after its remaining consumers are migrated. Remove `@shopify/polaris` only after no other route in scope imports it.

***

## Related guidance

* [Toast API](https://shopify.dev/docs/api/app-home/apis/user-interface-and-interactions/toast-api)
* [Migrate Frame from Polaris React](https://shopify.dev/docs/apps/build/app-home/migrate-from-polaris-react/frame)

***
