Skip to main content

Migrate ChoiceList from Polaris React

Replace Polaris React ChoiceList with s-choice-list and explicit s-choice children. Preserve whether the field accepts one value or multiple values, and keep the selected values in the same form or app state that performs the operation.

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 field in place during this migration slice.


Anchor to Migrate a choice listMigrate a choice list

The destination renders each choice directly instead of accepting a choices descriptor array.

Migrating multiple checkout choices

<s-choice-list label="Checkout options" name="checkout" multiple>
<s-choice value="shipping" selected>
Use the shipping address as the billing address by default
<s-text slot="details">
Reduces the number of fields required to check out. The billing address
can still be edited.
</s-text>
</s-choice>
<s-choice value="confirmation">
Require a confirmation step
<s-text slot="details">
Customers must review their order details before purchasing.
</s-text>
</s-choice>
</s-choice-list>
import {ChoiceList} from '@shopify/polaris';

export function CheckoutChoices({
selectedChoices = ['shipping'],
onChange,
}) {
return (
<ChoiceList
title="Checkout options"
allowMultiple
selected={selectedChoices}
onChange={onChange}
choices={[
{
label: 'Use the shipping address as the billing address by default',
value: 'shipping',
helpText: 'Reduces the number of fields required to check out. The billing address can still be edited.',
},
{
label: 'Require a confirmation step',
value: 'confirmation',
helpText: 'Customers must review their order details before purchasing.',
},
]}
/>
);
}

Preview


Anchor to Replace choice descriptorsReplace choice descriptors

Polaris ReactPolaris web componentsMigration notes
titlelabel on s-choice-listKeep a group label that describes the decision.
titleHiddenlabelAccessibilityVisibility="exclusive"Visually hide only a redundant label.
choicesExplicit s-choice childrenMove each descriptor's label to child content and keep its stable value.
Choice helpTexts-text slot="details" inside that s-choiceKeep explanation with the option it describes.
Choice disableddisabled on that s-choiceDisable only the unavailable option.
allowMultiplemultipleOmit it for a single-choice radio group.
selectedvalues on s-choice-listPass the controlled string array. For initial-only selection, use selected on child choices.
onChange(selected, name)onChange(event)Read the selected array from event.currentTarget.values.
errorerrorKeep the message at group level so it describes the complete decision.
disableddisabled on s-choice-listDisable the group and preserve the condition that controls availability.

Don't create a second descriptor array only to map it into s-choice elements. Render from the domain options that the app already uses, and derive selected state from one source.


Anchor to Choose single or multiple selectionChoose single or multiple selection

For single selection, omit multiple and store zero or one value in the values array. If the old code used individual RadioButton components, migrate the complete group to one choice list so the shared label and keyboard behavior remain intact.

For multiple selection, set multiple and treat values as an unordered set unless option order has domain meaning. Validate combinations at group level, such as requiring at least one value or preventing mutually exclusive choices.


  • Select every option with pointer and keyboard input.
  • Verify single-choice fields never retain more than one value.
  • Verify multiple-choice values submit with the expected name and stable values.
  • Test per-choice and whole-group disabled states.
  • Trigger and announce group errors, including required and invalid combinations.
  • Reload controlled forms and confirm the selected values restore correctly.

Anchor to Remove Polaris ReactRemove Polaris React

After every call site is migrated, remove ChoiceList, descriptor-only helpers, and callback adapters. Remove @shopify/polaris only after no other route in scope imports it.



Was this page helpful?