Select
Dropdown for selecting an option among different options.
The <Select> is a form component that allows you to select one or more elements from a list of predefined options. It should be used with other form components in a <Form>.
Anatomy
A <Select> is a labeled trigger that opens a popover with a list of options. The trigger shows the current selection and a chevron indicating the field is interactive. The popover opens below by default and flips above when there is no space.
- Label: Names the field above the trigger.
- Field: The pressable trigger that opens the popover.
- Selected value: The text rendered inside the trigger for the current selection. Falls back to a placeholder when nothing is selected.
- Description: Optional helper text below the field. Replaced by the error message when the field is invalid.
- Popover: The floating container that holds the list of options.
- Section header: Optional title for a group of related options that helps users scan the list.
- Option: A single choice in the list.
- Item label: The primary text of an option that names the choice.
- Item description: Optional secondary text within an option that helps the user decide.
Appearance
The appearance of a component can be customized using the variant and size props. These props adjust the visual style and dimensions of the component, available values are based on the active theme.
| Property | Type | Description |
|---|---|---|
variant | - | The available variants of this component. |
size | - | The available sizes of this component. |
Usage
The select should be used within a form. It supports an optional description which can be used to provide more context about the field.
As with all form components, the label should always describe what the user expects to achieve. If additional informations is required you can use the description to give a short information for displaying these, or you can provide a placeholder which should represent what is to select.
Number of options
If there are very few options (e.g., 1-4), consider using a radio group instead. These can be easier for users to scan and select.
A select is typically suitable for a moderate number of options (e.g., 5-15). This keeps the list manageable and quick to navigate.
When there are too many options (e.g., more than 15-20), usability can suffer. Users might find it cumbersome to scroll through a long list. In such cases, consider alternative approaches like a autocomplete or combobox.
Do
Don't
Don't use a select if there are less than 4 or more than 15 options to choose from.
With sections
When related options are present, organizing them into sections enhances clarity and usability. Grouping options provides additional context and helps users navigate choices more easily. This approach reduces complexity and allows for additional guidance when needed, ensuring a more intuitive experience.
This can be achieved by wrapping the options in the <Select.Section> component. A header is required for each section, which is set using the header prop.
import { Select } from '@marigold/components';export default () => ( <Select label="Genres"> {options.map(item => ( <Select.Section key={item.category} header={item.category}> {item.genres.map(genre => ( <Select.Option key={genre}>{genre}</Select.Option> ))} </Select.Section> ))} </Select>);const options = [ { category: 'Pop and Dance', genres: ['Pop', 'Electropop', 'Dance-pop', 'Teen pop', 'Disco'], }, { category: 'Rock and Alternative', genres: [ 'Hard rock', 'Punk rock', 'Alternative rock', 'Indie rock', 'Grunge', ], }, { category: 'Hip-Hop and R&B', genres: ['Hip-Hop', 'Rap', 'Trap', 'R&B'], },];Item description
If you need to have primary and secondary content shown within an option, compose the option with the <TextValue> and <Description> primitives. <TextValue> carries the option's label. <Description> provides the secondary line and is automatically wired to the option's aria-describedby for assistive tech.
import { Description, Select, TextValue } from '@marigold/components';export default () => ( <Select label="Permissions"> <Select.Option id="read" textValue="Read"> <TextValue>Read</TextValue> <Description>Read only</Description> </Select.Option> <Select.Option id="write" textValue="Write"> <TextValue>Write</TextValue> <Description>Read and write only</Description> </Select.Option> <Select.Option id="admin" textValue="Admin"> <TextValue>Admin</TextValue> <Description>Full access</Description> </Select.Option> </Select>);Disabled keys
Sometimes depending on other settings it can be that a select needs to have disabled options to show up. For this case you can set keys disabled through the disabledKeys property.
Keep in mind that you always should write information why a certain option is disabled near the disabled option.
import { Select } from '@marigold/components';export default () => ( <Select label="Shipping direction" disabledKeys={['germany', 'elsalvador', 'poland']} description="Please select the shipping direction, not every country can be available." > <Select.Option id="czechrepublic">Czech Republic</Select.Option> <Select.Option id="egypt">Egypt</Select.Option> <Select.Option id="elsalvador">El Salvador</Select.Option> <Select.Option id="germany">Germany</Select.Option> <Select.Option id="hungary">Hungary</Select.Option> <Select.Option id="india">India</Select.Option> <Select.Option id="nigeria">Nigeria</Select.Option> <Select.Option id="poland">Poland</Select.Option> <Select.Option id="portugal">Portugal</Select.Option> <Select.Option id="ukraine">Ukraine</Select.Option> </Select>);Multiselection
Sometimes you need to offer a way for users to select multiple options from a list, but you don't have much room in your layout. In these situations, enabling multiselection (selectionMode="multiple") on the <Select> is an effective approach. A common use case for this is when filtering a list of products. For instance, a user could select both a specific brand and a particular feature, and the dropdown would neatly contain both selections.
However, be mindful of the user experience when offering multiple selections. As more options are chosen, the display text will likely be truncated, hiding the full list of what's been selected. Note that for use cases requiring all selected options to be clearly visible, TagField is usually a better choice.
import { amenitiesOptions } from '@/lib/data/venues';import { Select } from '@marigold/components';export default () => ( <Select label="Amenities" width={72} selectionMode="multiple"> {amenitiesOptions.map(option => ( <Select.Option key={option} id={option}> {option} </Select.Option> ))} </Select>);Custom selected value
Add visual context to options by combining an avatar or icon with text. Pair the visual on the left with a name and short description on the right so users can scan the list quickly. Make sure options stay understandable without the visuals for accessibility purposes.
To keep the trigger compact while showing the full layout in the dropdown, pass a renderValue callback. It receives the selected items and replaces the default trigger render whenever something is selected. The placeholder still shows when nothing is selected.
The returned content must not include focusable or interactive elements. The trigger is itself a button.
import type { Person } from '@/lib/data/people';import { people } from '@/lib/data/people';import { Description, Inline, Select, Stack, Text, TextValue,} from '@marigold/components';export default () => ( <Select label="Assign to user" placeholder="Select a user" width="1/2" items={people} renderValue={([person]: Person[]) => ( <Inline space={2} alignY="center"> <img src={person.avatar} alt="" className="size-5 rounded-full object-cover" /> <Text>{person.name}</Text> </Inline> )} > {(person: Person) => ( <Select.Option id={person.id} textValue={person.name}> <Inline space={3} alignY="center"> <img src={person.avatar} alt={person.name} className="size-8 rounded-full object-cover" /> <Stack space={0}> <TextValue>{person.name}</TextValue> <Description>{person.position}</Description> </Stack> </Inline> </Select.Option> )} </Select>);Props
Select
Prop
Type
Accessibility props (4)
Prop
Type
DOM event handlers (64)
Prop
Type
Select.Option
Prop
Type
Accessibility props (1)
Prop
Type
DOM event handlers (63)
Prop
Type
Select.Section
Prop
Type
Accessibility props (1)
Prop
Type
DOM event handlers (64)
Prop
Type
Alternative components
Autocomplete: A searchfield that displays a dynamic list of suggestions. Useful when there are more than 15 options and you need to search for a specific value.
Combobox: A text field that allows the user to select values from a provided items array. Useful when there are mote than 15 options.
Radio: Component which allows to select only one option from a list. Use it if you have less than 5 options.