---
title: Migrate SettingToggle from Polaris React
description: >-
  Replace Polaris React SettingToggle with an immediately persisted s-switch or
  a checkbox in a submitted settings form.
source_url:
  html: >-
    https://shopify.dev/docs/apps/build/app-home/migrate-from-polaris-react/setting-toggle
  md: >-
    https://shopify.dev/docs/apps/build/app-home/migrate-from-polaris-react/setting-toggle.md
api_name: app-home
---

# Migrate Setting​Toggle from Polaris React

Replace Polaris React `SettingToggle` with `s-switch` when the setting applies immediately. Use `s-checkbox` when the value is part of a larger form that merchants save explicitly.

If the app renders this controlled field through React, upgrade to React 19 first. React 18 doesn't provide the custom-element property and event behavior this example relies on. If you can't upgrade yet, leave the controlled Polaris React setting in place during this migration slice.

***

## Migrate an immediate setting

## Migrating an enabled setting

##### Polaris web components

```tsx
import {useRef, useState} from 'react';

export function CustomerAccountsSetting({initialEnabled, persistEnabled}) {
  const [enabled, setEnabled] = useState(initialEnabled);
  const [pending, setPending] = useState(false);
  const confirmedValue = useRef(initialEnabled);
  const latestRequest = useRef(0);

  async function handleChange(event) {
    const nextEnabled = event.currentTarget.checked;
    const request = ++latestRequest.current;

    setEnabled(nextEnabled);
    setPending(true);

    try {
      await persistEnabled(nextEnabled);
      if (request === latestRequest.current) {
        confirmedValue.current = nextEnabled;
        shopify.toast.show('Customer account setting saved');
      }
    } catch {
      if (request === latestRequest.current) {
        setEnabled(confirmedValue.current);
        shopify.toast.show("Customer account setting couldn't be saved", {
          isError: true,
        });
      }
    } finally {
      if (request === latestRequest.current) setPending(false);
    }
  }

  return (
    <s-stack gap="small">
      <s-switch
        label="Customer accounts"
        details={`Customer accounts are ${enabled ? 'enabled' : 'disabled'}.`}
        checked={enabled}
        onChange={handleChange}
      />
      {pending && <s-text color="subdued">Saving setting…</s-text>}
    </s-stack>
  );
}
```

##### Polaris React

```tsx
import {useState} from 'react';
import {SettingToggle} from '@shopify/polaris';

export function CustomerAccountsSetting() {
  const [enabled, setEnabled] = useState(true);

  return (
    <SettingToggle
      enabled={enabled}
      action={{
        content: enabled ? 'Disable' : 'Enable',
        onAction: () => setEnabled((current) => !current),
      }}
    >
      Customer accounts are {enabled ? 'enabled' : 'disabled'}.
    </SettingToggle>
  );
}
```

***

## Replace Setting​Toggle responsibilities

| Polaris React | Polaris web components | Migration notes |
| - | - | - |
| `enabled` | `checked` on `s-switch` | Drive it from the last confirmed value. |
| `action.content` | Switch label, such as **Customer accounts** | A switch label names the setting, not the next action. |
| `action.onAction` | `onChange(event)` | Read `event.currentTarget.checked` and persist it. |
| `action.loading` | Adjacent pending status or temporarily disabled switch | Prevent overlapping writes and make progress visible. |
| `action.disabled` | `disabled` | Explain why the setting is unavailable. |
| `children` | `details` or visible text beside the switch | Keep consequences and prerequisites visible. |

For immediate persistence, keep the previous confirmed value until the request succeeds or optimistically update and roll back on failure. In either approach, reject stale responses when merchants toggle rapidly. Show an error toast or banner and leave a clear retry path.

For settings submitted together, use a named `s-checkbox` inside a native form and connect it to the same save bar as the other fields. Don't mix one immediate switch into an explicitly saved form without making that difference clear.

***

## Test the migration

* Toggle on and off through pending, success, failure, rollback, and retry.
* Toggle rapidly and verify stale responses don't overwrite the latest intent.
* Reload to confirm the backend value is authoritative.
* Exercise disabled permissions and prerequisites with visible explanation.
* Verify label, details, checked state, and errors are announced.

***

## Remove Polaris React

Remove `SettingToggle`, action descriptor builders, and duplicate enabled state after persistence uses the switch or form model. Remove `@shopify/polaris` only after no other route in scope imports it.

***

## Related guidance

* [Settings template](https://shopify.dev/docs/api/app-home/patterns/templates/settings)
* [Switch component](https://shopify.dev/docs/api/app-home/web-components/forms/switch)
* [Migrate Checkbox from Polaris React](https://shopify.dev/docs/apps/build/app-home/migrate-from-polaris-react/checkbox)

***
