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 Listbox | Polaris web components | Migration type |
|---|---|---|
| Compact single selection | s-select and s-option | Direct |
| Visible single or multiple choice | s-choice-list and s-choice | Change pattern |
| Shopify products, product variants, or collections | Resource Picker API | App Bridge |
| Other Shopify or app-specific resources | Picker API, or search plus a resource-list or index pattern | App Bridge or compose |
| Action commands | A trigger and s-menu | Change pattern |
Anchor to Migrate finite optionsMigrate finite options
Migrating a selectable option list
Polaris web components
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>
);
}Polaris React
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.
Anchor to Test the migrationTest the migration
- 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.
- Migrate OptionList from Polaris React
- Migrate Combobox from Polaris React
- Resource list pattern
- Index table pattern
- Picker API
- Resource Picker API