Components

Select

Choose one value from a short predefined list. Radix Select styled with Yuno tokens. Trigger matches Input (h-9, rounded-md, flat border).

Updated Jul 16, 2026 by Leonardo Posada

Anatomy

  1. 1
    Label

    Describes what is being selected. Sits above the trigger, same as any form field.

  2. 2
    Trigger

    The clickable pill. Shows the current value or placeholder + a trailing CaretDown.

  3. 3
    Content

    The popover with the option list. Elevated with shadow-lg on rounded-md. Portalled to the body.

  4. 4
    Item

    A single option. Focus state uses bg-accent. Selected shows a Check indicator on the right.

Form field

<div className="grid w-full max-w-sm gap-1.5">
  <Label htmlFor="currency">Currency</Label>
  <Select>
    <SelectTrigger id="currency">
      <SelectValue placeholder="Choose currency" />
    </SelectTrigger>
    <SelectContent>
      <SelectItem value="usd">USD - US Dollar</SelectItem>
      <SelectItem value="cop">COP - Colombian Peso</SelectItem>
      <SelectItem value="mxn">MXN - Mexican Peso</SelectItem>
      <SelectItem value="brl">BRL - Brazilian Real</SelectItem>
    </SelectContent>
  </Select>
</div>

With icons

<Select>
  <SelectTrigger className="w-64">
    <div className="flex items-center gap-2">
      <Globe weight="light" className="size-4 text-muted-foreground" />
      <SelectValue placeholder="Choose language" />
    </div>
  </SelectTrigger>
  <SelectContent>
    <SelectItem value="en">English</SelectItem>
    <SelectItem value="es">Español</SelectItem>
    <SelectItem value="pt">Português</SelectItem>
  </SelectContent>
</Select>

Groups

Long option lists group with SelectGroup + SelectLabel headers (all caps, muted). SelectSeparator draws a hairline between groups.

<Select>
  <SelectTrigger className="w-72">
    <SelectValue placeholder="Choose destination" />
  </SelectTrigger>
  <SelectContent>
    <SelectGroup>
      <SelectLabel>Latam</SelectLabel>
      <SelectItem value="co">Colombia</SelectItem>
      <SelectItem value="mx">Mexico</SelectItem>
      <SelectItem value="br">Brazil</SelectItem>
      <SelectItem value="ar">Argentina</SelectItem>
    </SelectGroup>
    <SelectSeparator />
    <SelectGroup>
      <SelectLabel>North America</SelectLabel>
      <SelectItem value="us">United States</SelectItem>
      <SelectItem value="ca">Canada</SelectItem>
    </SelectGroup>
    <SelectSeparator />
    <SelectGroup>
      <SelectLabel>Europe</SelectLabel>
      <SelectItem value="es">Spain</SelectItem>
      <SelectItem value="pt">Portugal</SelectItem>
      <SelectItem value="uk">United Kingdom</SelectItem>
    </SelectGroup>
  </SelectContent>
</Select>

Disabled options

<Select>
  <SelectTrigger className="w-64">
    <SelectValue placeholder="Choose plan" />
  </SelectTrigger>
  <SelectContent>
    <SelectItem value="starter">Starter</SelectItem>
    <SelectItem value="growth">Growth</SelectItem>
    <SelectItem value="scale" disabled>Scale (contact sales)</SelectItem>
  </SelectContent>
</Select>

States

Default
<Select>
  <SelectTrigger className="w-56"><SelectValue placeholder="Choose currency" /></SelectTrigger>
  <SelectContent>
    <SelectItem value="usd">USD</SelectItem>
    <SelectItem value="cop">COP</SelectItem>
  </SelectContent>
</Select>
Disabled
<Select disabled>
  <SelectTrigger className="w-56"><SelectValue placeholder="Managed by admin" /></SelectTrigger>
</Select>
Error

Please choose a plan to continue.

<Select>
  <SelectTrigger
    aria-invalid
    className="w-56 border-destructive focus:border-destructive focus:ring-destructive/30"
  >
    <SelectValue placeholder="Choose plan" />
  </SelectTrigger>
</Select>
<p className="text-xs text-destructive">Please choose a plan to continue.</p>

Required and optional

Yuno marks the odd one out. If most fields in a form are required, mark the few Optional ones with a small muted 'Optional' to the right of the Label. If most are optional, mark the required ones with a discrete 'Required' in the same spot. Never mix asterisks and Optional labels in the same form.

Optional
Optional
<div className="grid gap-1.5 w-full max-w-sm">
  <div className="flex items-center justify-between">
    <Label htmlFor="tz">Timezone</Label>
    <span className="text-xs text-muted-foreground">Optional</span>
  </div>
  <Select>
    <SelectTrigger id="tz"><SelectValue placeholder="Choose timezone" /></SelectTrigger>
    <SelectContent><SelectItem value="utc">UTC</SelectItem></SelectContent>
  </Select>
</div>
Required
Required
<div className="grid gap-1.5 w-full max-w-sm">
  <div className="flex items-center justify-between">
    <Label htmlFor="currency">Currency</Label>
    <span className="text-xs text-muted-foreground">Required</span>
  </div>
  <Select required>
    <SelectTrigger id="currency"><SelectValue placeholder="Choose currency" /></SelectTrigger>
    <SelectContent><SelectItem value="usd">USD</SelectItem></SelectContent>
  </Select>
</div>
Select vs Combobox vs Radio
Radio for 2–5 options where all should be visible. Select for 3–12 stable options that fit in a short menu. Combobox / Command for larger lists that need search.

Recipes

Ready-to-copy compositions covering the most common Yuno usages of this atom.

Currency picker

Short list of currencies inside a form. Trigger width matches sibling inputs.

<div className="grid gap-1.5 w-full max-w-sm">
  <Label htmlFor="currency">Currency</Label>
  <Select>
    <SelectTrigger id="currency"><SelectValue placeholder="Choose currency" /></SelectTrigger>
    <SelectContent>
      <SelectItem value="usd">USD</SelectItem>
      <SelectItem value="cop">COP</SelectItem>
      <SelectItem value="mxn">MXN</SelectItem>
    </SelectContent>
  </Select>
</div>
Country picker with groups

Countries grouped by region using SelectLabel + SelectSeparator to make long lists scannable.

<Select>
  <SelectTrigger className="w-72"><SelectValue placeholder="Choose country" /></SelectTrigger>
  <SelectContent>
    <SelectGroup>
      <SelectLabel>Latam</SelectLabel>
      <SelectItem value="co">Colombia</SelectItem>
      <SelectItem value="mx">Mexico</SelectItem>
    </SelectGroup>
    <SelectSeparator />
    <SelectGroup>
      <SelectLabel>Europe</SelectLabel>
      <SelectItem value="es">Spain</SelectItem>
    </SelectGroup>
  </SelectContent>
</Select>
Sort-by control

Compact select above a table or list. Leading Sort icon inside the trigger clarifies intent.

<Select defaultValue="newest">
  <SelectTrigger className="w-56">
    <div className="flex items-center gap-2">
      <ArrowsDownUp weight="light" className="size-4 text-muted-foreground" />
      <SelectValue />
    </div>
  </SelectTrigger>
  <SelectContent>
    <SelectItem value="newest">Newest first</SelectItem>
    <SelectItem value="oldest">Oldest first</SelectItem>
    <SelectItem value="amount">Highest amount</SelectItem>
  </SelectContent>
</Select>
Plan picker with disabled tier

Plans list where a tier is disabled with a hint text so the user knows it's not available.

<Select>
  <SelectTrigger className="w-64"><SelectValue placeholder="Choose plan" /></SelectTrigger>
  <SelectContent>
    <SelectItem value="starter">Starter</SelectItem>
    <SelectItem value="growth">Growth</SelectItem>
    <SelectItem value="scale" disabled>Scale (contact sales)</SelectItem>
  </SelectContent>
</Select>

Import

Copy this import line at the top of the file where you compose this atom.

Full Select surface + Label for the form-field pattern.
import {
  Select,
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectLabel,
  SelectSeparator,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { Label } from "@/components/ui/label";

Props

Everything else from the underlying HTML or Radix primitive is forwarded via ...props.

PropTypeDefaultDescription
value / defaultValuestringSelected item value. Radix keeps value as a string.
onValueChange(value: string) => voidFires when the user picks a new option.
disabledbooleanfalseApplied on <Select> or per <SelectItem> to disable individual options.
requiredbooleanfalseNative form validation. Pair with the 'Required' label pattern in this doc.
childrenSelectTrigger + SelectContent (with SelectGroup / SelectLabel / SelectItem / SelectSeparator)Compound API. See Groups section for the canonical structure.
SelectTrigger.classNamestringMerged via cn(). Use w-* utilities to set trigger width. Do not add shadow-*.

When to use

  • Choose one from 3–12 options (currency, country, status).
  • The list is stable and doesn't need search.
  • Inside a form, paired with a Label above the trigger.

When not to use

  • Fewer than 3 options — use RadioGroup or a segmented control.
  • More than ~12 or needs search — use Combobox / Command.
  • Multi-select — use a Checkbox group or a MultiSelect.
  • For actions (edit, delete, share) — that's a DropdownMenu.

Usage

Do
  • Provide a clear placeholder ('Choose currency').
  • Order options meaningfully (frequency, alphabetical, logical).
  • Keep the trigger width consistent with sibling inputs in the same form.
  • Use SelectGroup + SelectLabel to structure long lists into scannable sections.
Don't
  • Don't nest a Select inside another Select — it collapses on mobile.
  • Don't use a Select for actions — that's a DropdownMenu.
  • Don't apply drop shadow on the trigger — only border.
  • Don't rely on the trigger to fit long option labels — it will truncate.

Related

Cross-links to atoms and patterns you may reach for next.

  • Radio groupFor 2–5 options where all should be visible.
  • CommandFor long lists that need search.
  • Dropdown menuFor actions (edit / delete / share), not for choosing a value.
  • ComboboxCompose Command inside a Popover for a filterable select.