Choose one or more values from a dropdown menu.

import { Select } from "@/ui/select";

const fonts = [
  { label: "Inter", value: "inter" },
  { label: "Berkeley Mono", value: "berkeley-mono" },
  { label: "Libre Baskerville", value: "libre-baskerville" },
];

export default function SelectDemo() {
  return (
    <Select.Root items={fonts}>
      <Select.Trigger>
        <Select.Value placeholder="Select a font" />
        <Select.Icon />
      </Select.Trigger>
      <Select.Popup>
        <Select.ScrollUpArrow />
        <Select.List>
          {fonts.map((font) => (
            <Select.Item key={font.value} value={font.value}>
              <Select.ItemIndicator />
              <Select.ItemText>{font.label}</Select.ItemText>
            </Select.Item>
          ))}
        </Select.List>
        <Select.ScrollDownArrow />
      </Select.Popup>
    </Select.Root>
  );
}

A trigger opens a list of options and shows the chosen value.

Sizes

Three sizes to fit different layouts.

import { Select } from "@/ui/select";

const themes = [
  { label: "System", value: "system" },
  { label: "Light", value: "light" },
  { label: "Dark", value: "dark" },
];

const sizes = ["sm", "md", "lg"] as const;

export default function SelectSizesDemo() {
  return (
    <div className="flex flex-wrap items-end gap-3">
      {sizes.map((size) => (
        <Select.Root key={size} items={themes} defaultValue="system">
          <Select.Trigger size={size}>
            <Select.Value />
            <Select.Icon />
          </Select.Trigger>
          <Select.Popup>
            <Select.List>
              {themes.map((theme) => (
                <Select.Item key={theme.value} value={theme.value}>
                  <Select.ItemIndicator />
                  <Select.ItemText>{theme.label}</Select.ItemText>
                </Select.Item>
              ))}
            </Select.List>
          </Select.Popup>
        </Select.Root>
      ))}
    </div>
  );
}

Multiple

Let users choose more than one option.

"use client";

import { Select } from "@/ui/select";

const languages = [
  { label: "TypeScript", value: "ts" },
  { label: "Rust", value: "rust" },
  { label: "Go", value: "go" },
  { label: "Python", value: "py" },
  { label: "Swift", value: "swift" },
];

function renderValue(value: string[]) {
  if (value.length === 0) {
    return "Select languages";
  }
  if (value.length === 1) {
    return languages.find((language) => language.value === value[0])?.label;
  }
  return `${value.length} selected`;
}

export default function SelectMultipleDemo() {
  return (
    <Select.Root items={languages} multiple defaultValue={["ts", "rust"]}>
      <Select.Trigger>
        <Select.Value>{renderValue}</Select.Value>
        <Select.Icon />
      </Select.Trigger>
      <Select.Popup alignItemWithTrigger={false}>
        <Select.List>
          {languages.map((language) => (
            <Select.Item key={language.value} value={language.value}>
              <Select.ItemIndicator />
              <Select.ItemText>{language.label}</Select.ItemText>
            </Select.Item>
          ))}
        </Select.List>
      </Select.Popup>
    </Select.Root>
  );
}

Grouped

Organize options into labeled sections.

import { Fragment } from "react";
import { Select } from "@/ui/select";

const groups = [
  {
    value: "Fruits",
    items: [
      { label: "Apple", value: "apple" },
      { label: "Banana", value: "banana" },
      { label: "Orange", value: "orange" },
    ],
  },
  {
    value: "Vegetables",
    items: [
      { label: "Carrot", value: "carrot" },
      { label: "Spinach", value: "spinach" },
    ],
  },
];

export default function SelectGroupedDemo() {
  return (
    <Select.Root items={groups}>
      <Select.Trigger>
        <Select.Value placeholder="Select produce" />
        <Select.Icon />
      </Select.Trigger>
      <Select.Popup>
        <Select.List>
          {groups.map((group, index) => (
            <Fragment key={group.value}>
              <Select.Group>
                <Select.GroupLabel>{group.value}</Select.GroupLabel>
                {group.items.map((item) => (
                  <Select.Item key={item.value} value={item.value}>
                    <Select.ItemIndicator />
                    <Select.ItemText>{item.label}</Select.ItemText>
                  </Select.Item>
                ))}
              </Select.Group>
              {index < groups.length - 1 && <Select.Separator />}
            </Fragment>
          ))}
        </Select.List>
      </Select.Popup>
    </Select.Root>
  );
}

Icons

Show an icon next to each option.

import { Icon } from "@/ui/icon";
import { Select } from "@/ui/select";

const appearances = [
  {
    value: "system",
    label: (
      <>
        <Icon name="Monitor" />
        System
      </>
    ),
  },
  {
    value: "light",
    label: (
      <>
        <Icon name="Sun" />
        Light
      </>
    ),
  },
  {
    value: "dark",
    label: (
      <>
        <Icon name="Moon" />
        Dark
      </>
    ),
  },
];

export default function SelectIconsDemo() {
  return (
    <Select.Root items={appearances} defaultValue="system">
      <Select.Trigger>
        <Select.Value />
        <Select.Icon />
      </Select.Trigger>
      <Select.Popup>
        <Select.List>
          {appearances.map((appearance) => (
            <Select.Item key={appearance.value} value={appearance.value}>
              <Select.ItemIndicator />
              <Select.ItemText>{appearance.label}</Select.ItemText>
            </Select.Item>
          ))}
        </Select.List>
      </Select.Popup>
    </Select.Root>
  );
}

Avatars

Show an avatar next to each option.

import { Avatar } from "@/ui/avatar";
import { Select } from "@/ui/select";

const people = [
  { value: "lara", name: "Lara Tucci", initials: "LT", src: "https://i.pravatar.cc/80?img=5" },
  { value: "devon", name: "Devon Lane", initials: "DL", src: "https://i.pravatar.cc/80?img=12" },
  { value: "noah", name: "Noah Pierre", initials: "NP", src: "https://i.pravatar.cc/80?img=33" },
];

const items = people.map((person) => ({
  value: person.value,
  label: (
    <>
      <Avatar.Root data-slot="icon">
        <Avatar.Image src={person.src} alt={person.name} />
        <Avatar.Fallback>{person.initials}</Avatar.Fallback>
      </Avatar.Root>
      {person.name}
    </>
  ),
}));

export default function SelectAvatarsDemo() {
  return (
    <Select.Root items={items} defaultValue="lara">
      <Select.Trigger>
        <Select.Value />
        <Select.Icon />
      </Select.Trigger>
      <Select.Popup>
        <Select.List>
          {items.map((item) => (
            <Select.Item key={item.value} value={item.value}>
              <Select.ItemIndicator />
              <Select.ItemText>{item.label}</Select.ItemText>
            </Select.Item>
          ))}
        </Select.List>
      </Select.Popup>
    </Select.Root>
  );
}

Disabled

Disable the whole control or individual options.

import { Select } from "@/ui/select";

const plans = [
  { label: "Hobby", value: "hobby" },
  { label: "Pro", value: "pro" },
  { label: "Enterprise", value: "enterprise" },
];

export default function SelectDisabledDemo() {
  return (
    <div className="flex flex-wrap items-center gap-3">
      {/* The whole control is disabled. */}
      <Select.Root items={plans} defaultValue="pro" disabled>
        <Select.Trigger>
          <Select.Value />
          <Select.Icon />
        </Select.Trigger>
        <Select.Popup>
          <Select.List>
            {plans.map((plan) => (
              <Select.Item key={plan.value} value={plan.value}>
                <Select.ItemIndicator />
                <Select.ItemText>{plan.label}</Select.ItemText>
              </Select.Item>
            ))}
          </Select.List>
        </Select.Popup>
      </Select.Root>

      {/* A single option is disabled. */}
      <Select.Root items={plans} defaultValue="hobby">
        <Select.Trigger>
          <Select.Value />
          <Select.Icon />
        </Select.Trigger>
        <Select.Popup>
          <Select.List>
            {plans.map((plan) => (
              <Select.Item
                key={plan.value}
                value={plan.value}
                disabled={plan.value === "enterprise"}
              >
                <Select.ItemIndicator />
                <Select.ItemText>{plan.label}</Select.ItemText>
              </Select.Item>
            ))}
          </Select.List>
        </Select.Popup>
      </Select.Root>
    </div>
  );
}

Invalid

Shows an error state when the value is invalid.

import { Select } from "@/ui/select";

const sizes = [
  { label: "Small", value: "sm" },
  { label: "Medium", value: "md" },
  { label: "Large", value: "lg" },
];

export default function SelectInvalidDemo() {
  return (
    <Select.Root items={sizes}>
      <Select.Trigger data-invalid>
        <Select.Value placeholder="Select a size" />
        <Select.Icon />
      </Select.Trigger>
      <Select.Popup>
        <Select.List>
          {sizes.map((size) => (
            <Select.Item key={size.value} value={size.value}>
              <Select.ItemIndicator />
              <Select.ItemText>{size.label}</Select.ItemText>
            </Select.Item>
          ))}
        </Select.List>
      </Select.Popup>
    </Select.Root>
  );
}

API

Select.Trigger

PropTypeDefault
size"sm" | "md" | "lg""md"

Select.Popup

PropTypeDefault
sideOffsetnumber4
side"top" | "bottom" | "left" | "right""bottom"
align"start" | "center" | "end""center"
alignItemWithTriggerbooleantrue
containerHTMLElement | Ref | null-

Plus everything from Base UI Select, including items, value, defaultValue, and onValueChange. Select.Popup forwards the remaining positioner props.