Components / Controls
Select
Picks one option from a list that opens on demand. The trigger is a Cynosure button and the list opens in the top layer, so it is never clipped. For a short list that should stay visible, use RadioGroup.
When to useLink to "When to use"
- Five or more options, or a list that would take too much room as radios.
- A value that is submitted with a form (a country, a language, a database).
- Options that benefit from a description or an icon.
Use something else when:
- there are only a few options: RadioGroup or SegmentedControl
- the user types free text: TextField
UsageLink to "Usage"
import { Select } from "@arshad-shah/cynosure";
<Select
label="Fruit"
name="fruit"
placeholder="Choose a fruit"
options={[
{ value: "apple", label: "Apple" },
{ value: "pear", label: "Pear", description: "Seasonal" },
{ value: "plum", label: "Plum", disabled: true },
]}
onChange={setFruit}
/>Controlled useLink to "Controlled use"
Pass value and onChange(value) to own the state, or defaultValue to start with a selection.
Long lists and labelsLink to "Long lists and labels"
The list has a maximum height and scrolls. Long labels truncate with an ellipsis in the trigger and the list. The list opens above the trigger when there is no room below.
Options and statesLink to "Options and states"
variant:outline(default) orsoft.size:xs,sm,mdorlg.xsis a 20px trigger with smaller text and chevron for dense desktop chrome; it is still 24px to press (44px on coarse pointers) and its label is set as forsm.erroranddescription: shown under the field and linked to the trigger.labels: overrideplaceholder,empty(no options) andrequired(validation message).labelHidden: hides the label visually while it still names the trigger. Prefer a visible label.
Trailing text, dimmed options and a footer actionLink to "Trailing text, dimmed options and a footer action"
An option's trailing is drawn at the end of its row in the list, smaller and muted (a shortcut, a count); the trigger shows the label only. dimmed draws an option muted while it stays choosable. footer pins an action under the options, { label, icon?, onSelect }: it is the last option the arrow keys reach (End and PageDown too), and Enter, Space or a press closes the list and runs it. The value does not change, and Tab passes over it.
Coloured iconsLink to "Coloured icons"
iconTone and iconColor colour an option's icon and mean what Icon's tone and color mean: iconTone is a semantic colour (accent, neutral, danger, success, warning, info, muted), iconColor is any CSS colour and overrides it (brand draws a brand mark in its owner's colour). The colour shows in the list, on the highlighted and the selected option, and in the trigger once the option is chosen. Without the two fields an icon takes the text colour.
A disabled option shows its icon without the colour, muted with the rest of the row, and so does the trigger of a disabled Select. Tone colours keep a contrast of 3:1 against the highlight. With your own colour, check it in light and dark. The label must make sense without the colour.
PropsLink to "Props"
| Prop | What it does | Type | Default |
|---|---|---|---|
labelRequired | Names the control, shown above it. | ReactNode | |
optionsRequired | The choices: { value, label, description?, icon?, iconTone?, iconColor?, disabled?, dimmed?, trailing?, group? }. | SelectOption[] | |
labelHidden | Visually hide the label (it still names the control). Prefer visible labels. | boolean | |
description | Help text shown below the control. | ReactNode | |
error | Your own error; it replaces the built-in required message. | ReactNode | |
footer | An action pinned under the options ("Manage connections…"): the arrow keys' last stop, run with Enter, Space or a press. The list closes, focus returns to the trigger, and the value does not change. | OptionListAction | |
value | Controlled selected value. | string | |
defaultValue | Selected value at first, when uncontrolled. | string | |
onChange | Called with the chosen option's value when it changes. | ((value: string) => void) | |
placeholder | Shown while nothing is chosen. Default "Select…". | string | "Select…" |
name | Submits the value with its form under this name. | string | |
required | The form will not submit until a value is chosen; also draws the required marker. | boolean | |
disabled | Cannot be opened or changed, and is not submitted. | boolean | |
size | Height and text size of the control. Default "md". xs (about 20px) is for dense desktop chrome: the trigger is still 24px to press (44px on coarse pointers); its label is set as for sm. | DenseSize | "md" |
variant | outline, or soft (tinted, no border). Default "outline". | "soft" | "outline" | "outline" |
labels | Replace the built-in English text: the placeholder, the empty list and the required message. | { placeholder?: string; empty?: string; required?: string; } | |
className | Added to the root element, for layout. | string | |
style | Layout only. | CSSProperties | |
layout | stack puts the label above the control and the description and error below it. split puts the label and description at the start and the control at the end of one row (a settings row); when the field is too narrow for both, the control moves under the text. Default "stack". | "stack" | "split" | "stack" |
width | Width of the control, so the controls of a column of fields line up: "sm", "md" and "lg" are the --cy-field-control-width-* tokens (never wider than the field), "full" is the whole field. Default: the control's own width (the whole field in the stacked layout for TextField and the other fields). | FieldWidth |
Generated from the type definitions in @arshad-shah/cynosure 0.5.0.
Behaviour and accessibilityLink to "Behaviour and accessibility"
| Input | Result |
|---|---|
| Click, Enter, Space, ArrowDown, ArrowUp | Opens the list |
| Arrow keys, Home, End, PageUp, PageDown | Move through options, skipping disabled ones |
| Enter, Space, Tab | Select the active option (Enter and Space run the footer action when it is active) |
| Escape | Closes without changing the value |
| Typing | Jumps to a matching option (ignored during IME composition) |
- Pattern: a select-only combobox following the WAI-ARIA authoring practices, with a
listboxofoptions. - Forms: a hidden input carries
nameand the value, soFormData, reset andrequiredvalidation work. - Outside click: closes the list.
TouchLink to "Touch"
On coarse pointers (phones and tablets) option rows grow to 44px.
ThemingLink to "Theming"
Tokens: --cy-select-{radius,bg,border,list-bg,list-shadow,list-max-height,option-active-bg}; an xs trigger is --cy-control-height-xs tall. The list is an OptionList: the list-* and option-* tokens set its --cy-option-list-* tokens.
createTheme({ components: { select: { radius: "10px", listMaxHeight: "240px" } } });RelatedLink to "Related"
These examples run Cynosure 0.5.0 (commit 50ce30b), the version on npm.