Select
Select Examples
Custom Select (Material-ish): native <select> + trigger overlay + custom menu (listbox). Controlled open state via `open` + `onOpenChange`.
Controlled value + controlled open
Recommended setup: keep the selected `value` and the `open` state in React state. Use `onValueChange` to update the value, and `onOpenChange` to toggle/close the menu.
• This component controls visibility externally: you must pass `open` and update it via `onOpenChange`.
• Selecting an option triggers `onValueChange(value)` and then closes via `onOpenChange(false)`.
Preview
Selected: mx
Controlled Select
import {useState} from "react";
import Select from "@/packages/ui/src/_components/select/Select";
export default function Example() {
const [value, setValue] = useState<string | number>("mx");
const [open, setOpen] = useState(false);
return (
<Select
name="country"
label="Country"
placeholder="Select an option"
options={[
{value: "mx", label: "Mexico"},
{value: "us", label: "United States"},
{value: "ca", label: "Canada", disabled: true},
]}
value={value}
onValueChange={setValue}
open={open}
onOpenChange={setOpen}
extraTextContent="Helper text"
extraTextState="support"
/>
);
}Variants, sizes, and styles
Use `variant` for tone, `size` for density, and `style` for outlined/filled container.
• `open={false}` + `onOpenChange={() => null}` is a quick way to show the visual style without interactions in documentation previews.
Preview
Variants and sizes
import Select from "@/_components/select/Select";
const options = [
{value: "active", label: "Active"},
{value: "paused", label: "Paused"},
{value: "blocked", label: "Blocked"},
];
export default function Example() {
return (
<>
<Select
name="status"
label="Status"
variant="success"
size="large"
style="filled"
defaultValue="active"
open={false}
onOpenChange={() => null}
options={options}
/>
<Select
name="status_2"
label="Status"
variant="warning"
size="small"
style="outlined"
defaultValue="paused"
open={false}
onOpenChange={() => null}
options={options}
/>
</>
);
}Helper text states
When `extraTextContent` is provided, you can style it with `extraTextState`.
Preview
Helper text
Looks good
This field is required
Support / success / error
import {useState} from "react";
import Select from "@/_components/select/Select";
const options = [
{value: "mx", label: "Mexico"},
{value: "us", label: "United States"},
{value: "ca", label: "Canada", disabled: true},
];
export default function Example() {
const [open, setOpen] = useState(false);
return (
<>
<Select
name="support"
label="Support"
placeholder="Pick one"
options={options}
open={open}
onOpenChange={setOpen}
extraTextContent="Helper text"
extraTextState="support"
/>
<Select
name="error"
label="Error"
placeholder="Pick one"
options={options}
open={open}
onOpenChange={setOpen}
required
extraTextContent="This field is required"
extraTextState="error"
/>
</>
);
}Disabled and required
Use `disabled` to prevent opening and interactions. Use `required` to mark the field as required (adds attributes and classes).
Preview
Disabled / required
import {useState} from "react";
import Select from "@/_components/select/Select";
const options = [
{value: "mx", label: "Mexico"},
{value: "us", label: "United States"},
];
export default function Example() {
const [open, setOpen] = useState(false);
return (
<>
<Select
name="disabled"
label="Disabled"
options={options}
defaultValue="mx"
open={open}
onOpenChange={setOpen}
disabled
/>
<Select
name="required"
label="Required"
placeholder="Select an option"
options={options}
open={open}
onOpenChange={setOpen}
required
/>
</>
);
}Number values
Option values can be `string` or `number`. Your state can store either type.
• The internal native <select> is re-mounted using a key when the current value changes to avoid controlled/uncontrolled warnings.
Preview
Current: 2 (number)
Numeric values
import {useState} from "react";
import Select from "@/packages/ui/src/_components/select/Select";
const options = [
{value: 1, label: "One"},
{value: 2, label: "Two"},
{value: 3, label: "Three"},
];
export default function Example() {
const [value, setValue] = useState<string | number>(2);
const [open, setOpen] = useState(false);
return (
<Select
name="numbers"
label="Numbers"
options={options}
value={value}
onValueChange={setValue}
open={open}
onOpenChange={setOpen}
/>
);
}On this page
Select Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
| options | { value: string | number; label: string; disabled?: boolean }[] | Yes | — | Options to render in both native and custom menus. |
| value | string | number | No | undefined | Current value (used to compute the current selection). |
| defaultValue | string | number | No | undefined | Fallback value if `value` is not provided. |
| onValueChange | (value: string | number) => void | No | undefined | Called when a custom option is selected. Also closes the menu via `onOpenChange(false)`. |
| open | boolean | No | false | Whether the custom menu is open. |
| onOpenChange | (open: boolean) => void | No | undefined | Controls open state (trigger click, Enter/Space, Escape, option select). |
| variant | "primary" | "secondary" | "tertiary" | "success" | "warning" | "danger" | "info" | No | "primary" | Visual/semantic style (`cssnt-select--*`). |
| size | "small" | "medium" | "large" | No | "medium" | Size modifier (`cssnt-select--sm/md/lg`). |
| style | "outlined" | "filled" | No | "outlined" | Container style (`cssnt-select--outlined/filled`). |
| name | string | No | undefined | Used for `id` and `name` on the native select. Also used in the internal key (fallback is select). |
| label | string | No | undefined | Floating label. When a value exists (or when `placeholder` exists), the label elevates. |
| placeholder | string | No | undefined | If provided, inserts a disabled option value= in the native select and forces the label to elevate. |
| required | boolean | No | false | Adds `required` attribute and a `required` class on root and label. |
| disabled | boolean | No | false | Disables the trigger and prevents opening. Adds `is-disabled` class. |
| extraTextContent | string | No | undefined | Helper/extra text shown under the select. |
| extraTextState | "support" | "success" | "error" | No | "support" | Helper text style. |
| onChange | (...args: any[]) => any | No | undefined | Declared in the type, but not used by the component currently. |
| onClick | (...args: any[]) => any | No | undefined | Declared in the type, but not used by the component currently. |
Components