Features
- Supports multiple selection.
- Supports grouped options.
- Supports options with icons, avatars and descriptions.
- Compatible with our Form control component
- Adheres to our form accessibility guidelines.
When to use
Use a Select when users need to select one or multiple values from a large list of options. For small lists of options, consider using a Radio group or Checkbox group instead.
Examples
Label
The label of a form element should be clear and concise, ideally under three words. It should describe the value of the element and not what the user needs to do in order to fill it out properly.
<FormControl>
<FormControl.Label>Expense category</FormControl.Label>
<Select
name="expense-category"
placeholder="Choose category..."
options={[
{label: 'Travel', value: 'travel'},
{label: 'Entertainment', value: 'entertainment'},
{label: 'Equipment', value: 'equipment'},
]}
/>
</FormControl>Required or optional
Mark the minority of form elements in a form as required or optional. This helps users scan the form and understand what is required of them. Type out the word optional or required in the label. E.g. "Per purchase limit (optional)". Don't use asterisks or other symbols.
<FormControl>
<FormControl.Label>Expense category (required)</FormControl.Label>
<Select
isRequired
name="expense-category"
placeholder="Choose category..."
options={[
{label: 'Travel', value: 'travel'},
{label: 'Entertainment', value: 'entertainment'},
{label: 'Equipment', value: 'equipment'},
]}
/>
</FormControl>Hint text
Use hint text to give users clear guidance for data entry. Keep it brief and avoid repeating the label or other form details. If it feels redundant, try removing it. We keep help text above the input field to have the reading order match the visual order, which is needed for screen readers.
<FormControl>
<FormControl.Label>Expense category</FormControl.Label>
<FormControl.HintText>If no category applies, choose "Other"</FormControl.HintText>
<Select
name="expense-category"
placeholder="Choose category..."
options={[
{label: 'Travel', value: 'travel'},
{label: 'Entertainment', value: 'entertainment'},
{label: 'Other', value: 'other'},
]}
/>
</FormControl>Help popover
Use help popovers to aid first-time users or to clarify complex concepts. The help popover can contain interactive content and may be used to provide links for further information.
<FormControl>
<FormControl.LabelWrapper>
<FormControl.Label>Expense category</FormControl.Label>
<FormControl.Help>
Having all expenses tagged with a category helps us understand how we spend our money
and optimize our budget. Learn more about{' '}
<Link
target="_blank"
href="https://help.pleo.io/en/support/solutions/articles/103000254719-example-categories-for-pleo"
>
expense categories
</Link>
.
</FormControl.Help>
</FormControl.LabelWrapper>
<Select
name="expense-category"
placeholder="Choose category..."
options={[
{label: 'Travel', value: 'travel'},
{label: 'Entertainment', value: 'entertainment'},
{label: 'Other', value: 'other'},
]}
/>
</FormControl>Error
Provide clear and helpful error messages that guide users toward a solution. Instead of merely stating the problem, ensure the message is specific and actionable. Avoid vague or shaming language.
<FormControl>
<FormControl.Label>Expense category</FormControl.Label>
<Select
name="expense-category"
placeholder="Choose category..."
isInvalid
options={[
{label: 'Travel', value: 'travel'},
{label: 'Entertainment', value: 'entertainment'},
{label: 'Equipment', value: 'equipment'},
]}
/>
<FormControl.Error>Choose an expense category</FormControl.Error>
</FormControl>Disabled
Disable a form element to indicate that it’s currently unavailable. This can be used to maintain layout consistency and communicate that the element may become available later. If the form element will never be available in a given context, leave it out.
<FormControl>
<FormControl.Label>Expense category</FormControl.Label>
<Select
disabled
name="expense-category"
placeholder="Choose category..."
options={[
{label: 'Travel', value: 'travel'},
{label: 'Entertainment', value: 'entertainment'},
{label: 'Equipment', value: 'equipment'},
]}
/>
</FormControl>Clearable
Use a clearable select when you want to allow users to remove the selected value. This will show a "clear" ("x") button in the input field when a value is selected.
const options: SelectTypes.Option[] = [
{label: 'Travel', value: 'travel'},
{label: 'Entertainment', value: 'entertainment'},
{label: 'Equipment', value: 'equipment'},
]
const Example = () => {
const [value, setValue] = React.useState<SelectTypes.Option | null>(options[0])
return (
<FormControl>
<FormControl.Label>Expense category</FormControl.Label>
<Select
name="expense-category"
placeholder="Choose category..."
isClearable
value={value}
onChange={setValue}
options={options}
/>
</FormControl>
)
}
render(<Example />)Multi select
Use multi select to allow users to select multiple options from the list. For instance, you might want to allow users to tag an expense with multiple categories.
<FormControl>
<FormControl.Label>Expense category</FormControl.Label>
<Select
name="expense-category"
placeholder="Choose category..."
isMulti
options={[
{label: 'Travel', value: 'travel'},
{label: 'Entertainment', value: 'entertainment'},
{label: 'Equipment', value: 'equipment'},
]}
/>
</FormControl>Prefix icon
A prefix icon can be supplied to provide a visual cue about the type of options available. The icon will be shown when no option is selected, or if the options do not have icons of their own.
const options: SelectTypes.Option[] = [
{label: 'Travel', value: 'travel', icon: <CategoryTravel />},
{label: 'Entertainment', value: 'entertainment', icon: <CategoryEntertainment />},
{label: 'Equipment', value: 'equipment', icon: <CategoryEquipment />},
]
const Example = () => (
<FormControl>
<FormControl.Label>Expense category</FormControl.Label>
<Select
name="expense-category"
placeholder="Choose category..."
options={options}
PrefixIcon={CategoryNone}
isClearable
/>
</FormControl>
)
render(<Example />)Grouped options
Options can be separated into distinct groups (sections) with a label for each group. This is useful if you have options that belong to different categories.
const options: SelectTypes.GroupedSelectOption = [
{
label: 'Office expenses',
options: [
{label: 'Cleaning services', value: 'cleaning'},
{label: 'Snacks and beverages', value: 'snacks'},
],
},
{
label: 'Travel expenses',
options: [
{label: 'Flights', value: 'flights'},
{label: 'Hotels', value: 'hotels'},
],
},
]
const Example = () => (
<FormControl>
<FormControl.Label>Expense category</FormControl.Label>
<Select
name="grouped-expense-category"
placeholder="Choose category..."
options={options}
/>
</FormControl>
)
render(<Example />)Disabled options
Options can be disabled to prevent users from selecting them. This should be used when the option is not applicable in the current context. If an item is never applicable in a certain context, it should instead be excluded from the list of options.
<FormControl>
<FormControl.Label>Expense category</FormControl.Label>
<Select
name="expense-category"
placeholder="Choose category..."
options={[
{label: 'Travel', value: 'travel', disabled: true},
{label: 'Entertainment', value: 'entertainment'},
{label: 'Equipment', value: 'equipment'},
]}
/>
</FormControl>Option icons
Use option icons to provide visual cues about the type of options available. A common use case is for expense categories where icons can help users quickly identify an expense type.
const options: SelectTypes.Option[] = [
{
label: 'Travel',
value: 'travel',
icon: <CategoryTravel />,
},
{
label: 'Entertainment',
value: 'entertainment',
icon: <CategoryEntertainment />,
},
{
label: 'Equipment',
value: 'equipment',
icon: <CategoryEquipment />,
},
]
const Example = () => (
<FormControl>
<FormControl.Label>Expense category</FormControl.Label>
<Select name="expense-category" placeholder="Choose category..." options={options} />
</FormControl>
)
render(<Example />)Option descriptions
Use option descriptions to provide additional helpful details about the options available and/or in cases where the label alone may not be enough for users to distinguish between options.
const options: SelectTypes.Option[] = [
{
label: 'Equipment',
value: 'equipment',
description: 'Such as laptops, monitors, etc.',
},
{
label: 'Service',
value: 'service',
description: 'Such as consulting, legal, etc.',
},
{
label: 'Software',
value: 'software',
description: 'Such as subscriptions, licenses, etc.',
},
]
const Example = () => (
<FormControl>
<FormControl.Label>Expense category</FormControl.Label>
<Select name="expense-category" placeholder="Choose category..." options={options} />
</FormControl>
)
render(<Example />)Option avatars
We support avatars as a way to quickly identify items. By incorporating both a visual cue (e.g. the user's profile picture, or company logo) and textual information (the item label), this variation facilitates a quick and accurate selection of items from a list, enhancing user experience.
const options: SelectTypes.Option[] = [
{
label: 'Jeppe Rindom',
value: 'jeppe',
avatar: {src: jeppe, name: 'Jeppe Rindom'},
},
{
label: 'Nicollo Perra',
value: 'niccolo',
avatar: {src: niccolo, name: 'Nicollo Perra'},
},
]
const Example = () => (
<FormControl>
<FormControl.Label>Founder</FormControl.Label>
<Select
name="founder"
placeholder="Choose founder..."
PrefixIcon={User}
options={options}
isClearable
/>
</FormControl>
)
render(<Example />)Enlarged avatars
Avatars can be enlarged for enhanced visibility. These are meant to be used in combination with a description to provide additional details such as a user's role or department in situations where such information is useful or necessary for distinguishing between options.
const options: SelectTypes.Option[] = [
{
label: 'Jeppe Rindom',
value: 'jeppe',
description: 'Co-founder · CEO',
avatar: {src: jeppe, name: 'Jeppe Rindom', size: 40},
},
{
label: 'Nicollo Perra',
value: 'niccolo',
description: 'Co-founder · Engineering',
avatar: {src: niccolo, name: 'Nicollo Perra', size: 40},
},
]
const Example = () => (
<FormControl>
<FormControl.Label>Founder</FormControl.Label>
<Select
name="founder"
PrefixIcon={User}
placeholder="Choose founder..."
options={options}
isClearable
/>
</FormControl>
)
render(<Example />)Show value on hover
In cases where you many selects and want users to have quick access to the selected value, it can be useful to show the selected value when hovering over the select. When enabled, the full value will be shown after hovering the Select for a few seconds.
const options = [{label: 'Maximilian Alexander Montgomery Beauregard III ', value: 'max'}]
const Example = () => (
<FormControl>
<FormControl.Label>Expense category</FormControl.Label>
<Select
showValueOnHover
name="expense-category"
placeholder="Choose category..."
value={options[0]}
options={options}
maxWidth="250px"
/>
</FormControl>
)
render(<Example />)Use interpunct separators
When displaying multiple data points within a single select option, use an interpunct (·) as a separator. This helps to visually distinguish between different pieces of information while maintaining a clean and organized appearance.
const options: SelectTypes.Option[] = [
{
label: 'Jeppe Rindom · CEO',
value: 'jeppe',
},
{
label: 'Nicollo Perra · Engineering',
value: 'niccolo',
},
]
const Example = () => (
<FormControl>
<FormControl.Label>Founder</FormControl.Label>
<Select
name="founder"
placeholder="Choose founder..."
value={options[0]}
options={options}
/>
</FormControl>
)
render(<Example />)Async
Use the async version of our Select component when options need to be loaded dynamically as the user types—ideal for large lists or data fetched from remote sources. The component displays a loading indicator while retrieving options to keep the experience responsive.
The async Select supports text-based filtering, but does not support infinite scrolling. The underlying library doesn't provide this feature, and we've concluded that users are unlikely to scroll through very long lists (100+ items) when they can refine results directly within the input.
const options: SelectTypes.Option[] = [
{label: 'Travel', value: 'travel'},
{label: 'Entertainment', value: 'entertainment'},
{label: 'Equipment', value: 'equipment'},
]
const Example = () => (
<FormControl>
<FormControl.Label>Category</FormControl.Label>
<Select
isAsync
placeholder="Type to search..."
defaultMenuIsOpen={false}
defaultOptions={options}
loadingLabel="Loading categories..."
noOptionsMessage={({inputValue}) => `No "${inputValue}" category found`}
loadOptions={(
inputValue: string,
callback: (options: SelectTypes.Option[]) => void,
) => {
// Simulate a network request
setTimeout(() => {
callback(
options.filter((option) =>
option.label.toLowerCase().includes(inputValue.toLowerCase()),
),
)
}, 1000)
}}
/>
</FormControl>
)
render(<Example />)Creatable
Creatable Select lets users add new options directly from the dropdown when their input doesn't match any existing choices. This supports flexible workflows, such as quickly adding a missing item or triggering a flow to create a new entry.
const Example = () => {
const [value, setValue] = React.useState<SelectTypes.Option | null>(null)
const [options, setOptions] = React.useState<SelectTypes.Option[]>([
{label: 'Pizza ApS', value: 'pizza'},
{label: 'Schnitzl GmbH', value: 'schnitzl'},
{label: 'Pasta S.r.l.', value: 'pasta'},
])
return (
<FormControl>
<FormControl.Label>Supplier</FormControl.Label>
<Select
options={options}
isCreatable
value={value}
onChange={setValue}
createLabel={(inputValue) => `Create "${inputValue}"`}
CreateIcon={Plus}
onCreateOption={(inputValue) => {
setOptions([...options, {label: inputValue, value: inputValue}])
setValue({label: inputValue, value: inputValue})
}}
/>
</FormControl>
)
}
render(<Example />)Accessibility
The implementation of this component has been informed by our form accessibility guidelines.
Best practices
Refer to our Forms guidelines for general advice on forms structure, validation, and more.
Related components
- Checkbox group: A form element that enables users to select multiple values from a list of options.
- Form control: Form control displays a labelled input and, optionally, associated validation text, help popover, and/or hint text.
- Radio group: A form element that enables users to select a single value from a list of options.