Select
Choose one or several options from a dropdown list.
Examples
Use options with unique nonempty string values. onChange returns the value and option; clearing returns an empty string and undefined. Arrow keys highlight options, Enter selects, Escape closes and Tab moves on.
import { Select } from '@sudden3/leaf-ui';
const options = [
{ label: 'Design studio', value: 'design' },
{ label: 'Product team', value: 'product' },
{ label: 'Engineering team', value: 'engineering' },
{ label: 'Archived project', value: 'archived', disabled: true },
];
export function SelectBasic() {
return (
<div className="leaf-demo-stack">
<Select aria-label="Choose a team" options={options} placeholder="Select a team" />
<Select aria-label="Default team" options={options} defaultValue="design" />
<Select aria-label="Disabled team" options={options} disabled defaultValue="product" />
</div>
);
}
import { Select } from '@sudden3/leaf-ui';
import { useState } from 'react';
export function SelectControlled() {
const [value, setValue] = useState('');
return (
<div className="leaf-demo-stack">
<Select
aria-label="Project visibility"
value={value}
placeholder="Select visibility"
allowClear
onChange={setValue}
options={[
{ label: 'Public', value: 'public' },
{ label: 'Team', value: 'team' },
{ label: 'Private', value: 'private' },
]}
/>
<span className="leaf-demo-note">Current:{value || 'Not selected'}</span>
<Select
aria-label="Team required"
status="error"
placeholder="Select a team"
options={[{ label: 'Design team', value: 'design' }]}
/>
</div>
);
}
Open the list to see its purple theme and border radius. import { ConfigProvider, type LeafTheme, Select } from '@sudden3/leaf-ui';
const theme: LeafTheme = {
primaryColor: '#7654c6',
borderRadius: 6,
};
export function SelectTheme() {
return (
<ConfigProvider className="leaf-demo-stack" theme={theme}>
<Select
aria-label="Themed team"
allowClear
defaultValue="design"
options={[
{ value: 'design', label: 'Design studio' },
{ value: 'product', label: 'Product team' },
]}
/>
<span className="leaf-demo-note">
Open the list to see its purple theme and border radius.
</span>
</ConfigProvider>
);
}
import { Button, type ControlSize, Input, Select } from '@sudden3/leaf-ui';
export function ControlSizes() {
return (
<div className="leaf-demo-stack leaf-demo-stack--wide">
{(['sm', 'md', 'lg'] as const).map((size: ControlSize) => (
<div key={size} className="leaf-demo-control-row">
<span className="leaf-demo-size">{size}</span>
<Input size={size} aria-label={`${size} Search`} placeholder="Search projects" />
<Select
size={size}
aria-label={`${size} Status`}
defaultValue="all"
options={[
{ label: 'All statuses', value: 'all' },
{ label: 'In progress', value: 'active' },
]}
/>
<Button size={size}>Search</Button>
</div>
))}
</div>
);
}
Search and multiple selection
showSearch filters existing options; multiple accepts an array and keeps the menu open while choosing.
import { Select, type SelectOption } from '@sudden3/leaf-ui';
import { useState } from 'react';
const options: SelectOption[] = [
{ value: 'design', label: 'Design' },
{ value: 'engineering', label: 'Engineering' },
{ value: 'marketing', label: 'Marketing' },
];
export function SelectSearch() {
const [teams, setTeams] = useState<string[]>(['design']);
return (
<div className="leaf-demo-stack">
<Select
aria-label="Search teams"
showSearch
allowClear
options={options}
placeholder="Type to search"
/>
<Select
aria-label="Choose several teams"
multiple
showSearch
allowClear
options={options}
value={teams}
onChange={setTeams}
/>
<output className="leaf-demo-note">{teams.join(', ') || '—'}</output>
</div>
);
}
Popup width and content
import { Select, type SelectOption } from '@sudden3/leaf-ui';
const options: SelectOption[] = [
{ value: 'garden', label: 'Leaf Garden Design System' },
{ value: 'studio', label: 'Leaf Studio' },
{ value: 'notes', label: 'Leaf Notes' },
];
export function SelectPopup() {
return (
<div className="leaf-demo-stack">
<Select
aria-label="Automatic popup width"
style={{ width: 180 }}
options={options}
defaultValue="studio"
/>
<Select
aria-label="Fixed popup width"
popupWidth={300}
popupMaxWidth={360}
style={{ width: 180 }}
options={options}
optionRender={(option) => (
<div>
<strong>{option.label}</strong>
<div style={{ fontSize: 12, opacity: 0.65 }}>{option.value}</div>
</div>
)}
/>
<Select
aria-label="Selection limit"
multiple
options={options}
defaultValue={['studio', 'notes']}
maxCount={2}
maxTagCount={1}
allowClear
/>
<Select aria-label="Loading options" options={[]} loading placeholder="Loading" />
<Select aria-label="Empty options" options={[]} notFoundContent="No projects yet" />
</div>
);
}
Select API
SelectOption
Types
Import SelectProps to describe component props. Option types in the API table link to their detailed fields above.
import type { SelectProps, SelectOption } from '@sudden3/leaf-ui';
Use name to include values in FormData. Uncontrolled fields follow form reset; reset controlled values in application state. Place controls in FormField for labels, help and errors. ConfigProvider supplies regional themes and translated built-in UI. Application labels and options are your responsibility.
In multiple mode, clearing returns []. FormData submits repeated values under the same name; read them with formData.getAll(name). Empty-query Backspace removes the last enabled tag. Leaving clears the query; searches never create values. For node labels, supply searchLabel. The ref and other input attributes target the input.
The field keeps its layout width. The popup is at least as wide as the field and grows to fit its options, up to popupMaxWidth. Use popupWidth="trigger" for a matching width or set popupWidth={300} for a fixed width. Content wraps only after reaching its width limit.