Skip to main content

select

Displays a list of options for the user to pick from - triggered by a button.

Philosophy

Native selects are accessible but difficult to style consistently. This select builds on @gentleduck/primitives/select which provides full keyboard navigation, ARIA semantics, scroll management, and typeahead search. The wrapper adds design-system styling while the primitive handles all interaction logic.

How It's Built

Loading diagram...

Installation


npx @gentleduck/cli add select

npx @gentleduck/cli add select

Usage

import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select"
<Select>
  <SelectTrigger className="w-[180px]">
    <SelectValue placeholder="Theme" />
  </SelectTrigger>
  <SelectContent>
    <SelectItem value="light">Light</SelectItem>
    <SelectItem value="dark">Dark</SelectItem>
    <SelectItem value="system">System</SelectItem>
  </SelectContent>
</Select>

Examples

Scrollable

Form

Active Trigger on Open

Style the trigger to appear active while the select dropdown is open using data-[state=open]:

Component Composition

Loading diagram...

RTL Support

Set the direction once with DirectionProvider (or <html dir="rtl">) and the select follows. The portaled listbox gets the resolved dir, so text, the check indicator, and alignment mirror without any extra props.

Motion

Use MotionSelect and MotionSelectContent for smooth enter/exit animations powered by motion. The dropdown enters and exits with a scaleIn preset (fade, scale, and blur) and a bouncy spring transition. MotionSelectTrigger adds tap feedback (scale 0.97) to the trigger button.

API Reference

Select

The root component that manages open/closed state, value state, and provides context.

PropTypeDefaultDescription
valuestring-Controlled selected value
defaultValuestring-Initial value (uncontrolled)
onValueChange(value: string) => void-Callback fired when the selected value changes
openboolean-Controlled open state
defaultOpenbooleanfalseInitial open state (uncontrolled)
onOpenChange(open: boolean) => void-Callback fired when dropdown open state changes
dir'ltr' | 'rtl'-Text direction. Resolved by primitives useDirection (dir prop -> DirectionProvider -> <html dir>).
namestring-Name attribute for native form submission
disabledboolean-Disables the entire select
requiredboolean-Marks the select as required for form validation
formstring-Associates the select with a form element by ID
autoCompletestring-Hint for browser autofill

SelectTrigger

Button that toggles the dropdown. Renders a styled <button> with a chevron icon.

PropTypeDefaultDescription
classNamestring-Additional CSS class names
disabledboolean-Disables the trigger

Sets role="combobox", aria-expanded, aria-controls, aria-autocomplete="none", and data-state automatically.

SelectValue

Renders the selected value text, or a placeholder when nothing is selected.

PropTypeDefaultDescription
placeholderReact.ReactNode''Text shown when no value is selected

SelectContent

The dropdown content area. Handles positioning, focus management, keyboard navigation, and dismiss behavior.

PropTypeDefaultDescription
position'item-aligned' | 'popper''popper'Positioning strategy. item-aligned aligns selected item with trigger. popper uses floating positioning.
side'top' | 'right' | 'bottom' | 'left''bottom'Preferred side (popper position only)
sideOffsetnumber-Offset from trigger on the main axis
align'start' | 'center' | 'end''start'Alignment on the cross axis
alignOffsetnumber-Offset on the cross axis
avoidCollisionsbooleantrueWhether to flip to avoid viewport overflow
collisionPaddingnumber10Padding from viewport edges
classNamestring-Additional CSS class names

Exposes data-state="open" / data-state="closed" and data-side for CSS animation.

SelectGroup

Groups related items together. Renders a <div> with role="group".

PropTypeDefaultDescription
classNamestring-Additional CSS class names

SelectLabel

Label for a SelectGroup. Renders a <div> linked to its group via aria-labelledby.

PropTypeDefaultDescription
classNamestring-Additional CSS class names

SelectItem

An individual selectable item. Renders a <div> with role="option".

PropTypeDefaultDescription
valuestring(required)The value representing this item. Must not be empty string.
disabledbooleanfalseWhether the item is disabled
textValuestring-Optional text override for typeahead search
classNamestring-Additional CSS class names

Exposes data-state="checked" / data-state="unchecked", data-highlighted, and data-disabled.

SelectSeparator

Visual separator between items. Renders a styled <div>.

PropTypeDefaultDescription
classNamestring-Additional CSS class names

SelectScrollUpButton / SelectScrollDownButton

Scroll navigation buttons that appear when content overflows the viewport.

PropTypeDefaultDescription
classNamestring-Additional CSS class names

MotionSelect

Same props as Select. Wraps the root with motion state management for enter/exit animations. Required when using MotionSelectContent.

MotionSelectContent

Same props as SelectContent. Adds a scaleIn enter/exit animation (fade, scale, and blur) with a springBouncy transition, mounted and unmounted via useMotionRoot/useMotionMount for exit-animation support. Must be used with MotionSelect root. Requires the motion package.

MotionSelectTrigger

Same props as SelectTrigger. Wraps the trigger with whileTap press feedback (scale 0.97). Requires the motion package.

PropTypeDefaultDescription
...propsISelectTriggerProps-All props from SelectTrigger are supported