Select
Choose one option from a popup list.
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue } from '@youj/react'
Installation & usage
npm i @youj/reactFor an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.
Use Select for one value from a list, such as a region or role. For a short list, a Radio Group keeps every option visible. Use a Command list when people need to search.
In the Next.js App Router, render this from a Client Component, a file that starts with 'use client': it takes functions (onValueChange), and a Server Component can't pass those. Server rendering has the rest.
import { Field, FieldLabel, Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@youj/react'
const roles = [
{ value: 'admin', label: 'Admin' },
{ value: 'member', label: 'Member' },
{ value: 'viewer', label: 'Viewer' },
]
export function RoleSelect() {
return (
<Field>
<FieldLabel>Role</FieldLabel>
<Select items={roles} defaultValue="member" name="role">
<SelectTrigger className="w-full">
<SelectValue />
</SelectTrigger>
<SelectContent>
{roles.map((role) => (
<SelectItem key={role.value} value={role.value}>
{role.label}
</SelectItem>
))}
</SelectContent>
</Select>
</Field>
)
}Pass items, either an array of { value, label } or an object that maps values to labels, so the trigger can show the chosen label before the popup has ever opened. Without it, the labels are read from the SelectItems written inside the Select. Items that a component of your own renders can't be read, so there SelectValue would show the raw value, and development warns once to pass items.
Description
A function region Select with regions grouped by continent.
SelectGroup with a SelectLabel titles a run of options, and SelectSeparator draws a hairline between groups. Items can hold more than text: in the demo, each region carries its code in muted type. Keep a space between the label and the extra text, so the option's accessible name reads "Frankfurt fra1".
A placeholder, sizes and states.
SelectValue takes a placeholder for when nothing is chosen. size="sm" fits toolbars and dense forms. By default the popup opens over the trigger with the chosen option lined up on it. Pass alignItemWithTrigger={false} to open it below the trigger, like a menu. disabled and invalid go on the Field, and a FieldError explains what's wrong.
A select that takes several values.
With multiple, the value is an array: each option toggles, and the popup stays open until you close it. The trigger lists the chosen labels, separated by commas. Give SelectValue a function of the value to write a shorter summary, like "Failed deployments and 2 more".
A borderless picker inside a card.
variant="soft" drops the edge and fills the trigger with the theme's quiet band, with the same corner and height as any field, a hover step and the usual focus ring. Use it for a picker that sits inside a card or panel (a model, category or sort picker), where the card already frames it. The fill is a little under 3:1 against the card, so the chevron and the value identify the control rather than an edge: keep the default outlined field where a select has to read on its own, such as in a form. ghost goes further and has no fill until hover.
A status picker on each row of a list, with no chevron.
hideIcon leaves out the trigger's chevron, for a row of selects where the value alone says it opens (an issue's status, a table cell). With variant="ghost" and size="sm" the trigger is just its value until hover. It stays a combobox, named by its aria-label and reporting aria-expanded, so nothing changes for the keyboard or a screen reader. Keep the chevron where a select stands alone.
<SelectTrigger variant="ghost" size="sm" hideIcon aria-label="Status of ENG-188">
<SelectValue />
</SelectTrigger>Code
select-demo.tsx, the Demo story. The component itself comes from the package.
Reference
Propssize, presentation (2)
Props
Select
Select adds no props of its own. They pass through to SelectPrimitive.Root.Props<Value, Multiple>.
It takes Base UI's items, value, defaultValue, onValueChange, open, onOpenChange, multiple, disabled, readOnly, required and name. The required default comes from the surrounding Field.
SelectTrigger
| Prop | Type | |
|---|---|---|
size | 'sm' | 'default'default 'default' | 'default' |
variant | 'default' | 'ghost' | 'soft'
default 'default' | 'default' |
hideIcon | booleanLeaves out the chevron, for a dense row of selects (a table cell, a property list) where the value alone shows it opens. The trigger keeps its role, name and default false | false |
SelectContent
| Prop | Type | |
|---|---|---|
presentation | OverlayPresentation'auto''sheet''popover'
default 'auto' | 'auto' |
The popup's position comes from side, sideOffset, align, alignOffset and alignItemWithTrigger, which default to bottom, 6, center, 0 and true.
MotionOpen, open over the trigger, close… · reduced motion
Motion
| Moment | Tokens | ||
|---|---|---|---|
| Openscales from 96% and fades in, from its transform origin | duration.fastease.enter140ms · cubic-bezier(0.16, 1, 0.3, 1) | 140mscubic-bezier(0.16, 1, 0.3, 1) | |
| Open over the triggerfades only | duration.fastease.enter140ms · cubic-bezier(0.16, 1, 0.3, 1) | 140mscubic-bezier(0.16, 1, 0.3, 1) | |
| Close | duration.instantease.exit80ms · cubic-bezier(0.4, 0, 1, 1) | 80mscubic-bezier(0.4, 0, 1, 1) | |
| Chevronturns over while open | spring.snappy0.2s, bounce 0 | 0.2s, bounce 0 | |
| Scroll arrowsfade in and out on long lists | duration.fastease.standard140ms · cubic-bezier(0.2, 0, 0, 1) | 140mscubic-bezier(0.2, 0, 0, 1) |
Reduced motion
The popup appears and closes at once, and the chevron flips without turning.
The popup wears motion's yj-pop preset. When it opens lined up over the trigger, it only fades: growing out of the option you're already looking at reads as a jump.
Reduced motion
The popup opens and closes without scaling or fading, and the chevron flips straight to its new direction. The highlighted and chosen options still show the same way.
AccessibilityKeyboard, ARIA, focus
Accessibility
- The trigger is a
comboboxthat opens alistbox.Space,EnterandArrowDownopen it, and typing jumps to a matching option. - In the popup, the arrow keys,
HomeandEndmove the highlight,Enterchooses, andEscapecloses and returns focus to the trigger. - A
FieldLabelnames the trigger, and aFieldDescriptionorFieldErrordescribes it. Outside aField, give the trigger anaria-label. - A
FieldErrorrenders as analert, so it's announced when it appears.