Skip to main content

Migrate Listbox from Polaris React

Polaris web components don't have a general-purpose listbox primitive. Choose a supported control or pattern instead of rebuilding Polaris React Listbox one subcomponent at a time.

When Listbox is nested inside Polaris React Combobox, migrate the pair as one interaction. Follow the Combobox migration first; don't replace the listbox separately while leaving the old combobox responsible for focus, input, and open state.

Existing ListboxPolaris web componentsMigration type
Compact single selections-select and s-optionDirect
Visible single or multiple choices-choice-list and s-choiceChange pattern
Shopify products, product variants, or collectionsResource Picker APIApp Bridge
Other Shopify or app-specific resourcesPicker API, or search plus a resource-list or index patternApp Bridge or compose
Action commandsA trigger and s-menuChange pattern

Anchor to Migrate finite optionsMigrate finite options

Migrating a selectable option list

function CheckoutOptions({selected, toggleOption}) {
return (
<s-choice-list
label="Checkout options"
labelAccessibilityVisibility="exclusive"
name="checkout"
values={selected}
multiple
onChange={(event) => toggleOption(event.currentTarget.values)}
>
<s-choice value="shipping">Use shipping address for billing</s-choice>
<s-choice value="confirmation">Require a confirmation step</s-choice>
</s-choice-list>
);
}
import {Listbox} from '@shopify/polaris';

<Listbox allowMultiple onSelect={toggleOption}>
<Listbox.Option value="shipping" selected={selected.includes('shipping')}>
Use shipping address for billing
</Listbox.Option>
<Listbox.Option value="confirmation" selected={selected.includes('confirmation')}>
Require a confirmation step
</Listbox.Option>
</Listbox>

Preview


Anchor to Replace Listbox responsibilitiesReplace Listbox responsibilities

Map option value, label, disabled state, and supporting text to explicit destination children. Put the group label, selected values, required state, and error on the containing select or choice list.

Don't carry Listbox.Option, Listbox.Action, Listbox.Section, or Listbox.Loading into a compatibility component. Actions belong in a menu or visible buttons; sections of complex results usually indicate a resource pattern; remote loading belongs to the query that owns results.

For remote results, implement search, cancellation or stale-response protection, loading, empty, error, pagination, selected IDs, and create-new behavior together. Use the debounce and AbortController pattern in the Filters migration, then render results with the resource list pattern or index table pattern. Don't assemble an s-popover with buttons and call it a listbox unless the custom implementation supplies complete focus, selection, typeahead, and keyboard semantics.


  • Select, deselect, restore, and submit stable values.
  • Verify single-select controls never retain multiple values.
  • Exercise disabled options and group errors.
  • Test rapid remote search through loading, empty, failure, and stale responses.
  • Verify keyboard behavior and accessible group and option names.

Anchor to Remove Polaris ReactRemove Polaris React

Remove Listbox, its subcomponent imports, option descriptors, and custom context once the complete workflow uses the destination control or pattern. Remove @shopify/polaris only after no other route in scope imports it.



Was this page helpful?