Skip to main content
Migrate to Polaris

Version 2025-07 is the last API version to support React-based UI components. Later versions use web components, native UI elements with built-in accessibility, better performance, and consistent styling with Shopify's design system. Check out the migration guide to upgrade your extension.

Select

The Select component provides a dropdown menu for choosing a single value from a predefined list of options. It supports option groups, placeholder text, disabled and read-only states, and inline validation errors.

For visible radio/checkbox lists, use ChoiceList.

Support
Targets (46)

Supported targets


Props for the Select component, a form control that lets the user choose one value from a predefined list of options presented in a dropdown menu.

Anchor to label
label
string
required

The visible label displayed above the select field. This label is also used by assistive technologies to describe the field.

Anchor to options
options
( | )[]
required

The options a user can select from, provided as an array of OptionDescription or OptionGroupDescription objects. Each option requires a label and value.

Anchor to disabled
disabled
boolean

Whether the select is disabled. When true, the field can't be interacted with and appears in a dimmed state.

Anchor to error
error
string

An error message to display beneath the field. When set, the field receives a specific stylistic treatment to communicate a problem that needs to be resolved immediately.

string

A unique identifier for the field. When no id is set, a globally unique value will be used instead.

string

An identifier for the field that is unique within the nearest containing Form component. This value is used when submitting the form data.

Anchor to onBlur
onBlur
() => void

A callback that fires when the field loses focus. Use this to trigger validation or other side effects when the user moves away from the select.

Anchor to onChange
onChange
(value: string) => void

A callback that fires whenever the selected option changes. The callback receives the string value of the newly selected option. This component is controlled, so you must store this value in state and reflect it back in the value prop.

Anchor to onFocus
onFocus
() => void

A callback that fires when the field receives focus. Use this to trigger side effects when the user interacts with the select.

Anchor to placeholder
placeholder
string

A short hint that describes the expected value of the field. The placeholder is displayed when no value is set, giving the user guidance on what to select.

Anchor to readOnly
readOnly
boolean

Whether the field is read-only. When true, the current value can't be changed by the user but the field remains focusable and its value is still included in form submissions.

Anchor to required
required
boolean

Whether the field requires a value. This adds semantic meaning to the field for assistive technologies, but it won't cause an error to appear automatically. If you want to present an error when this field is empty, use the error prop.

Anchor to value
value
string

The currently selected value. This should match the value property of one of the items in the options array. When not set, the value defaults to an empty string, which displays the placeholder text as the selected value.


Anchor to Assign warehouse locationAssign warehouse location

Assign a product to a warehouse location from a dropdown of four regions. This example uses Select with four warehouse options, and a Button that assigns the warehouse and closes the modal.

Assign warehouse location

Assign a product to a warehouse location from a dropdown of four regions. This example uses `Select` with four warehouse options, and a [Button](/docs/api/admin-extensions/2025-07/ui-components/actions/button) that assigns the warehouse and closes the modal.

Assign warehouse location

import {useState} from 'react';
import {reactExtension, useApi, Select, Button, BlockStack} from '@shopify/ui-extensions-react/admin';

function App() {
const {data, close} = useApi('admin.product-details.action.render');
const productId = data.selected[0]?.id;
const [warehouse, setWarehouse] = useState('');

return (
<BlockStack>
<Select
label="Assign warehouse"
name="warehouse"
value={warehouse}
options={[
{label: 'East Coast — New York', value: 'nyc'},
{label: 'West Coast — Los Angeles', value: 'lax'},
{label: 'Central — Chicago', value: 'chi'},
{label: 'International — London', value: 'lon'},
]}
onChange={setWarehouse}
/>
<Button
variant="primary"
onPress={async () => {
await fetch('/api/products/warehouse', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({productId, warehouse}),
});
close();
}}
>
Assign warehouse
</Button>
</BlockStack>
);
}

export default reactExtension(
'admin.product-details.action.render',
() => <App />,
);
import {extension, Select, Button, BlockStack} from '@shopify/ui-extensions/admin';

export default extension(
'admin.product-details.action.render',
(root, api) => {
const {data, close} = api;
const productId = data.selected[0]?.id;
let warehouse = '';

const stack = root.createComponent(BlockStack);

const field = root.createComponent(Select, {
label: 'Assign warehouse',
name: 'warehouse',
options: [
{label: 'East Coast — New York', value: 'nyc'},
{label: 'West Coast — Los Angeles', value: 'lax'},
{label: 'Central — Chicago', value: 'chi'},
{label: 'International — London', value: 'lon'},
],
onChange: (value) => {
warehouse = value;
},
});

const saveButton = root.createComponent(
Button,
{
variant: 'primary',
onPress: async () => {
await fetch('/api/products/warehouse', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({productId, warehouse}),
});
close();
},
},
'Assign warehouse',
);

stack.appendChild(field);
stack.appendChild(saveButton);
root.appendChild(stack);
},
);

Anchor to Add placeholder prompt textAdd placeholder prompt text

Guide merchants to make a selection by adding a placeholder that appears before any option is chosen. This example uses a placeholder message in a product classification dropdown, making it clear that a selection is expected.

Add placeholder prompt text

import {reactExtension, Select, BlockStack, Text} from '@shopify/ui-extensions-react/admin';

function App() {

return (
<BlockStack>
<Text fontWeight="bold">Product classification</Text>
<Select
label="Product category"
name="category"
placeholder="Select a category…"
options={[
{label: 'Electronics', value: 'electronics'},
{label: 'Apparel', value: 'apparel'},
{label: 'Home & Garden', value: 'home-garden'},
{label: 'Health & Beauty', value: 'health-beauty'},
{label: 'Food & Beverage', value: 'food-beverage'},
]}
/>
</BlockStack>
);
}

export default reactExtension(
'admin.product-details.block.render',
() => <App />,
);
import {extension, Select, BlockStack, Text} from '@shopify/ui-extensions/admin';

export default extension(
'admin.product-details.block.render',
(root) => {

const stack = root.createComponent(BlockStack);

const heading = root.createComponent(
Text,
{fontWeight: 'bold'},
'Product classification',
);

const field = root.createComponent(Select, {
label: 'Product category',
name: 'category',
placeholder: 'Select a category…',
options: [
{label: 'Electronics', value: 'electronics'},
{label: 'Apparel', value: 'apparel'},
{label: 'Home & Garden', value: 'home-garden'},
{label: 'Health & Beauty', value: 'health-beauty'},
{label: 'Food & Beverage', value: 'food-beverage'},
],
});

stack.appendChild(heading);
stack.appendChild(field);
root.appendChild(stack);
},
);

Anchor to Validate required selection on submitValidate required selection on submit

Validate that a required select field has a value before submission using the error prop. This example shows an inline error when merchants attempt to save without choosing a shipping class, preventing incomplete data from reaching your backend.

Validate required selection on submit

import {useState} from 'react';
import {reactExtension, useApi, Select, Button, BlockStack} from '@shopify/ui-extensions-react/admin';

function App() {
const {data, close} = useApi('admin.product-details.action.render');
const productId = data.selected[0]?.id;
const [shippingClass, setShippingClass] = useState('');
const [error, setError] = useState(undefined);

return (
<BlockStack>
<Select
label="Shipping class"
name="shippingClass"
required
value={shippingClass}
error={error}
options={[
{label: 'Standard (5-7 days)', value: 'standard'},
{label: 'Express (2-3 days)', value: 'express'},
{label: 'Overnight', value: 'overnight'},
{label: 'Freight', value: 'freight'},
]}
onChange={(value) => {
setShippingClass(value);
setError(undefined);
}}
/>
<Button
variant="primary"
onPress={async () => {
if (!shippingClass) {
setError('Please select a shipping class');
return;
}
await fetch('/api/products/shipping-class', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({productId, shippingClass}),
});
close();
}}
>
Save shipping class
</Button>
</BlockStack>
);
}

export default reactExtension(
'admin.product-details.action.render',
() => <App />,
);
import {extension, Select, Button, BlockStack} from '@shopify/ui-extensions/admin';

export default extension(
'admin.product-details.action.render',
(root, api) => {
const {data, close} = api;
const productId = data.selected[0]?.id;
let shippingClass = '';

const stack = root.createComponent(BlockStack);

const field = root.createComponent(Select, {
label: 'Shipping class',
name: 'shippingClass',
required: true,
options: [
{label: 'Standard (5-7 days)', value: 'standard'},
{label: 'Express (2-3 days)', value: 'express'},
{label: 'Overnight', value: 'overnight'},
{label: 'Freight', value: 'freight'},
],
onChange: (value) => {
shippingClass = value;
field.updateProps({error: undefined});
},
});

const saveButton = root.createComponent(
Button,
{
variant: 'primary',
onPress: async () => {
if (!shippingClass) {
field.updateProps({error: 'Please select a shipping class'});
return;
}
await fetch('/api/products/shipping-class', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({productId, shippingClass}),
});
close();
},
},
'Save shipping class',
);

stack.appendChild(field);
stack.appendChild(saveButton);
root.appendChild(stack);
},
);

  • Use Select for four or more options: When there are only two or three options, use a ChoiceList with radio buttons instead because all options are visible without interaction.
  • Order options logically: Arrange options in an order that makes sense to merchants, such as alphabetically, by popularity, or by a natural sequence. Place the most common choice first when there's no inherent order.
  • Use option groups for long lists: When the list has many options, group related items using option groups to make scanning easier.
  • Write a clear label: The required label prop describes what the selection controls. Use specific labels like "Country" or "Sort by".
  • Use a placeholder when no default makes sense: Set the placeholder prop (like "Select a country") when there's no obvious default value. This communicates that the merchant needs to make a choice.

  • Select supports single selection only. For multi-selection, use a ChoiceList with multiple set to true.
  • The dropdown options can't be customized with colors, icons, or rich content.
  • Select doesn't support search or filtering within the options list. For large option sets, use option groups to help merchants find items faster.
  • Dynamic loading of options as the user scrolls isn't supported.

Was this page helpful?