Skip to content
Components

Select

A form element that enables users to select a single or multiple values from a list of options.
Choose category...

Features

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

Information:
We promote usage of this component in combination with our Form control component to maintain layout consistency and ensure form accessibility. The Form control supports advanced use cases such as hint text, help popovers and error messages.

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.

Information:
Never omit a label. Form labels are required for accessibility purposes. However, it may be acceptable to hide the label visually in certain cases.
Show code
<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.

Show code
<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.

Show code
<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.

Show code
<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.

Show code
<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.

Show code
<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.

Show code
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.

Show code
<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.

Show code
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.

Show code
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.

Show code
<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.

Show code
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.

Show code
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.

Show code
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.

Show code
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.

Show code
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.

Show code
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.

Information:

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.

Show code
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.

Show code
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.

  • 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.
Didn't find what you were looking for?
Edit this page