arrow_drop_down_circle

Select

Dropdown selector for predefined options.

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

Select — Props
PropTypeRequiredDefaultDescription
options{ value: string | number; label: string; disabled?: boolean }[]YesOptions to render in both native and custom menus.
valuestring | numberNoundefinedCurrent value (used to compute the current selection).
defaultValuestring | numberNoundefinedFallback value if `value` is not provided.
onValueChange(value: string | number) => voidNoundefinedCalled when a custom option is selected. Also closes the menu via `onOpenChange(false)`.
openbooleanNofalseWhether the custom menu is open.
onOpenChange(open: boolean) => voidNoundefinedControls 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`).
namestringNoundefinedUsed for `id` and `name` on the native select. Also used in the internal key (fallback is select).
labelstringNoundefinedFloating label. When a value exists (or when `placeholder` exists), the label elevates.
placeholderstringNoundefinedIf provided, inserts a disabled option value= in the native select and forces the label to elevate.
requiredbooleanNofalseAdds `required` attribute and a `required` class on root and label.
disabledbooleanNofalseDisables the trigger and prevents opening. Adds `is-disabled` class.
extraTextContentstringNoundefinedHelper/extra text shown under the select.
extraTextState"support" | "success" | "error"No"support"Helper text style.
onChange(...args: any[]) => anyNoundefinedDeclared in the type, but not used by the component currently.
onClick(...args: any[]) => anyNoundefinedDeclared in the type, but not used by the component currently.