Skip to main content

Migrate to the Polaris checkbox component

The Polaris checkbox component renders a checkbox input. It replaces the previous Checkbox component and is available as <s-checkbox> in API versions 2025-10 and newer.


The following properties are different in the Polaris checkbox component.

The previous Checkbox onChange prop now receives an Event instead of the new boolean value. Read the checked state from event.currentTarget.checked.

Migrating onChange

import '@shopify/ui-extensions/preact';
import {render} from 'preact';

export default function extension() {
render(<Extension />, document.body);
}

function Extension() {
return (
<s-checkbox
label="I agree to the terms"
onChange={(event) => {
console.log('Checked:', event.currentTarget.checked);
}}
/>
);
}
import {
reactExtension,
Checkbox,
} from '@shopify/ui-extensions-react/checkout';

export default reactExtension(
'purchase.checkout.block.render',
() => <Extension />,
);

function Extension() {
return (
<Checkbox onChange={(value) => console.log('Checked:', value)}>
I agree to the terms
</Checkbox>
);
}

The previous Checkbox value prop was a boolean alias for checked, used to drive the controlled checked state. On the Polaris checkbox, use checked for controlled usage, or defaultChecked to set only the initial state for uncontrolled usage.

Migrating value

import '@shopify/ui-extensions/preact';
import {render} from 'preact';
import {useState} from 'preact/hooks';

export default function extension() {
render(<Extension />, document.body);
}

function Extension() {
const [isChecked, setIsChecked] = useState(true);

return (
<s-checkbox
label="I agree to the terms"
checked={isChecked}
onChange={(event) => setIsChecked(event.currentTarget.checked)}
/>
);
}
import {
reactExtension,
Checkbox,
} from '@shopify/ui-extensions-react/checkout';
import {useState} from 'react';

export default reactExtension(
'purchase.checkout.block.render',
() => <Extension />,
);

function Extension() {
const [isChecked, setIsChecked] = useState(true);

return (
<Checkbox value={isChecked} onChange={setIsChecked}>
I agree to the terms
</Checkbox>
);
}

The Polaris checkbox repurposes value as a string used as the form submission value, and it's only submitted when the checkbox is checked. Pair it with name to participate in form submission:

Using value for form submission

<s-checkbox
label="I agree to the terms"
name="terms"
value="accepted"
/>

The Polaris checkbox component introduces the following new properties:

New propTypeDescription
command'--auto' | '--show' | '--hide' | '--toggle'Sets the action to run on the target component when the checkbox is activated.
commandForstringSets the ID of the target component for the command.
defaultCheckedbooleanSets the initial checked state for uncontrolled usage.
labelstringSets the checkbox's visible label. Replaces the previous children pattern. For rich label content (text with inline links), use the label slot instead — see children below.
requiredbooleanAdds semantic meaning that the field needs a value. It doesn't trigger automatic validation or display an error — set the error property to present an error when the checkbox is empty.

The previous Checkbox component accepted any element as children to render the visible label, which allowed composing the label from text, inline components, or formatting. The Polaris checkbox doesn't render children. Migrate based on the label content:

  • Plain string labels — use the label property.
  • Rich label content (text combined with inline <s-link>) — provide an <s-text> element with slot="label". When present, the slot takes precedence over the label property.

The label slot's direct child must be a single <s-text> element. Inside that <s-text>, you can include text and inline <s-link> elements — any other elements are stripped to keep the label safe to render inside the underlying <label> element.

Migrating children to label (string)

import '@shopify/ui-extensions/preact';
import {render} from 'preact';

export default function extension() {
render(<Extension />, document.body);
}

function Extension() {
return <s-checkbox label="I agree to the terms" />;
}
import {
reactExtension,
Checkbox,
} from '@shopify/ui-extensions-react/checkout';

export default reactExtension(
'purchase.checkout.block.render',
() => <Extension />,
);

function Extension() {
return <Checkbox>I agree to the terms</Checkbox>;
}

Migrating children to the label slot (rich content)

import '@shopify/ui-extensions/preact';
import {render} from 'preact';

export default function extension() {
render(<Extension />, document.body);
}

function Extension() {
return (
<s-checkbox>
<s-text slot="label">
I agree to the <s-link href="/terms">terms</s-link>
</s-text>
</s-checkbox>
);
}
import {
reactExtension,
Checkbox,
Link,
Text,
} from '@shopify/ui-extensions-react/checkout';

export default reactExtension(
'purchase.checkout.block.render',
() => <Extension />,
);

function Extension() {
return (
<Checkbox>
<Text>
I agree to the <Link to="/terms">terms</Link>
</Text>
</Checkbox>
);
}

The previous Checkbox toggles prop has been replaced by the command and commandFor props. Point commandFor at an <s-details> element, and the checkbox will expand or collapse it when toggled.

Previous patternNew pattern
toggles="gift-message"command="--toggle" + commandFor="gift-message" targeting an <s-details>.

Migrating toggles to command

import '@shopify/ui-extensions/preact';
import {render} from 'preact';

export default function extension() {
render(<Extension />, document.body);
}

function Extension() {
return (
<>
<s-checkbox
label="Add a gift message"
command="--toggle"
commandFor="gift-message"
/>
<s-details id="gift-message">
<s-text-field label="Gift message" />
</s-details>
</>
);
}
import {
reactExtension,
Checkbox,
Disclosure,
TextField,
View,
} from '@shopify/ui-extensions-react/checkout';

export default reactExtension(
'purchase.checkout.block.render',
() => <Extension />,
);

function Extension() {
return (
<Disclosure>
<Checkbox toggles="gift-message">Add a gift message</Checkbox>
<View id="gift-message">
<TextField label="Gift message" />
</View>
</Disclosure>
);
}

Was this page helpful?