Skip to content

Shadcn Select

The shadcn/ui Select lets users pick one option from a list, styled with Tailwind CSS v4. It replaces the native select with an accessible, keyboard-navigable menu that supports groups, labels, and a placeholder. Selects appear in checkout, contact, and filter flows across ShadcnStore blocks.

Key features

  • Accessible, keyboard-navigable single-choice menu with type-ahead.
  • Groups, labels, and a placeholder value.
  • items on the root maps values to labels for SelectValue display.
  • Controlled or uncontrolled via value / defaultValue.
  • Renders in a portal to avoid clipping inside dialogs and cards.
  • alignItemWithTrigger on SelectContent aligns the highlighted item with the trigger.

Installation

bash
npx shadcn@latest add select

Usage

Pass items on the Select root so SelectValue shows the option label (e.g. "Apple") instead of the raw value (e.g. "apple").

tsx
import {
  Select,
  SelectTrigger,
  SelectValue,
  SelectContent,
  SelectItem,
  SelectGroup,
  SelectLabel,
} from "@/components/ui/select"

const fruits = [
  { label: "Apple", value: "apple" },
  { label: "Banana", value: "banana" },
]

export function Example() {
  return (
    <Select items={fruits}>
      <SelectTrigger className="w-[180px]">
        <SelectValue placeholder="Select a fruit" />
      </SelectTrigger>
      <SelectContent>
        <SelectGroup>
          <SelectLabel>Fruits</SelectLabel>
          {fruits.map((fruit) => (
            <SelectItem key={fruit.value} value={fruit.value}>
              {fruit.label}
            </SelectItem>
          ))}
        </SelectGroup>
      </SelectContent>
    </Select>
  )
}

Grouped options

tsx
const fruits = [
  { label: "Apple", value: "apple" },
  { label: "Banana", value: "banana" },
  { label: "Blueberry", value: "blueberry" },
  { label: "Grapes", value: "grapes" },
]

<Select items={fruits}>
  <SelectTrigger className="w-[200px]">
    <SelectValue placeholder="Select a fruit" />
  </SelectTrigger>
  <SelectContent>
    <SelectGroup>
      <SelectLabel>Fruits</SelectLabel>
      {fruits.map((fruit) => (
        <SelectItem key={fruit.value} value={fruit.value}>
          {fruit.label}
        </SelectItem>
      ))}
    </SelectGroup>
  </SelectContent>
</Select>

Controlled value

tsx
const fruits = [
  { label: "Apple", value: "apple" },
  { label: "Banana", value: "banana" },
]
const [value, setValue] = useState("")

<Select items={fruits} value={value} onValueChange={setValue}>

</Select>

Scrollable

With a long list of options, the content area scrolls and keeps scroll buttons at the edges. No extra configuration is needed.

tsx
const timezoneItems = timezones.map((tz) => ({ label: tz, value: tz }))

<Select items={timezoneItems}>
  <SelectTrigger>…</SelectTrigger>
  <SelectContent>
    <SelectGroup>
      <SelectLabel>Timezone</SelectLabel>
      {timezoneItems.map((tz) => (
        <SelectItem key={tz.value} value={tz.value}>{tz.label}</SelectItem>
      ))}
    </SelectGroup>
  </SelectContent>
</Select>

Disabled

Disable the whole control with disabled on Select, or a single option with disabled on SelectItem.

tsx
const fruits = [
  { label: "Apple", value: "apple" },
  { label: "Banana", value: "banana" },
]

<Select items={fruits} disabled>…</Select>

<SelectItem value="banana" disabled>Banana (out of stock)</SelectItem>

Positioning

SelectContent accepts alignItemWithTrigger (defaults to true) so the highlighted option lines up with the trigger when the menu opens. Set it to false if you prefer the menu to open from the top of the list.

tsx
<SelectContent alignItemWithTrigger={false}>…</SelectContent>

Accessibility

  • The trigger exposes the current value; always provide a SelectValue with a placeholder so an empty select still has a readable state.
  • Pass items on the root so the displayed label matches what users see in the list.
  • The menu is fully keyboard-operable: open with Enter or Space, move with arrow keys, and type-ahead jumps to matching options.
  • Pair the trigger with a Label in forms so the control has an accessible name.

When to use the Select

Use a Select when the user picks one value from a short, known list: country, currency, status, or category. For long lists or when users know what they want and would rather type, use a Combobox with search. For a handful of visible options, a Radio Group may read better than a Select, and for multiple choices use Checkboxes or a multi-select.

Used in these blocks

A Select sits inside a Form beside Input fields, and often within a Dialog or Card. For grouped action menus rather than value selection, use a Dropdown Menu.

FAQ

What is the shadcn select used for?

The Select lets users pick one option from a list, such as a country, currency, or category. It replaces the native select with a styled, accessible menu.

What is the difference between Select and Combobox?

Select is for choosing from a short, fixed list. Combobox adds type-to-filter search and suits long or async option sets.

How do I control the selected value?

Pass value and onValueChange to the Select root, or use defaultValue for an uncontrolled starting value. Always pass items so the trigger shows the correct label.

Why is my Select content clipped inside a dialog?

The content renders in a portal by default, which avoids clipping. If you changed that, ensure the container does not have overflow: hidden around the trigger.

Why does SelectValue show the raw value instead of the label?

Pass items on the Select root with label and value for each option. Without items, SelectValue displays the raw value string.