Skip to main content

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


Anchor to Migrate an immediate settingMigrate an immediate setting

Migrating an enabled setting

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

Preview


Anchor to Replace SettingToggle responsibilitiesReplace SettingToggle responsibilities

Polaris ReactPolaris web componentsMigration notes
enabledchecked on s-switchDrive it from the last confirmed value.
action.contentSwitch label, such as Customer accountsA switch label names the setting, not the next action.
action.onActiononChange(event)Read event.currentTarget.checked and persist it.
action.loadingAdjacent pending status or temporarily disabled switchPrevent overlapping writes and make progress visible.
action.disableddisabledExplain why the setting is unavailable.
childrendetails or visible text beside the switchKeep 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.


  • 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.

Anchor to Remove Polaris ReactRemove 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.



Was this page helpful?