// preview in
saved for every page

Select

Picks one option, or a few, from a list that stays closed until needed. The popup follows the skin through the portal and opens with the keyboard as well as the pointer.

Built on Base UIPattern WAI-ARIA Listbox (select-only combobox)Client componentSource ↗

Installation

Set up Camaleo once (Installation), then import the parts you need; add SelectGroup, SelectGroupLabel and SelectSeparator for long lists. The skin you load styles the trigger and the popup.

import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from "@camaleo/react";

Anatomy

Select holds the state; the trigger shows the value; the content is a popup rendered in a portal. Every part has a data-slot you can target from CSS.

Brazil⌄
[data-slot="select-trigger"][data-slot="select-value"] · chevron[data-slot="select-popup"] › [data-slot="select-item"]

Examples

Every example is a real file you can copy. They all wear the skin, mode and brand from the bar above.

minimal · light · #3fa34d

With a placeholder

Leave out defaultValue when the choice is the person's to make; SelectValue placeholder says what to pick without pretending it is a value.

Groups and separators

Past eight or so options, SelectGroup with a SelectGroupLabel lets people jump to the right section instead of reading every row.

Aligned with the trigger

alignItemWithTrigger opens the list over the trigger with the current option in place, so short lists feel like a native menu.

Arrives Nov 10–14 · $5.90

Controlled

Pick another option. With value and onValueChange the rest of the form can react, here the delivery date and price under the field.

Several values

multiple keeps the list open and returns an array; give SelectValue a function so the trigger reads "Mon, Wed, Fri" instead of a count.

XL is back on Nov 20.

Unavailable options

Disable an option rather than removing it, so people learn it exists, and say when it comes back.

Choose a state to calculate shipping.

Required, with an error

Inside a Field, the label names the trigger and FieldError is announced with it; say what to do, not just that it is wrong.

In context

A select is rarely alone. These are whole pieces of UI you can copy, in the skin you picked.

Filters

Filter panelCard · Field · Select · Switch · Button
Shipping address
Country and stateFieldset · Field · Select · Input

1–25 of 312

Rows per pageField · Select · IconButton · Text

Guidelines

DoA visible label above it.

The label stays put after a value is chosen, so people always know what the field is.

Don’tThe placeholder as the label.

Once something is picked, "Country" disappears and the field has no name on screen.

Billing
DoTwo or three options? Show them all.

Radios cost one click and nothing is hidden.

Don’tHiding two options in a popup.

It takes two clicks to see a choice that would fit on one line.

Props

PropTypeDefaultDescription
alignItemWithTriggerbooleanfalsePlace the popup over the trigger with the selected item aligned (macOS style). Off, it opens below the trigger.
renderReactElement | (props, state) => ReactElement—Allows you to replace the component's HTML element with a different tag, or compose it with another component. Accepts a ReactElement or a function that returns the element to render.
finalFocusboolean | RefObject | (type) => …—Where focus goes when the popup closes. By default, back to the trigger.

These are the props of SelectContent. Select takes Base UI's root props: items (a record or { label, value }[], so the trigger shows the label before the popup opens), value, defaultValue, onValueChange, multiple, disabled, required, readOnly, name and open / onOpenChange. SelectItem takes value and disabled; SelectValue takes placeholder or a function of the value as children.

Styling hooks

Restyle it without forking: target the attributes, or set the tokens on a parent, a skin or the select itself.

Attributes

data-slot"select-trigger" · "select-value" · "select-positioner" · "select-popup" · "select-list" · "select-item" · "select-group" · "select-group-label" · "select-separator"
data-popup-openon the trigger while the popup is open
data-placeholderon the value while nothing is chosen
data-highlightedon the item under the keyboard or pointer
data-selectedon the chosen item(s)
data-disabledon a disabled trigger or item
data-invalidon the trigger inside an invalid Field

Tokens it reads

Color

--cml-border--cml-border-control--cml-danger--cml-fg--cml-fg-muted--cml-field-bg--cml-field-border-sides--cml-field-shadow--cml-focus-ring--cml-item-highlight-fg--cml-item-highlight-shadow--cml-popover-bg--cml-popover-border--cml-shadow-popover--cml-surface-raised

Shape & size

--cml-border-width--cml-field-border-width--cml-field-height--cml-field-padding--cml-font-size-field--cml-gap--cml-item-height--cml-item-padding--cml-popover-border-width--cml-popover-padding--cml-radius-control--cml-radius-field--cml-radius-item--cml-radius-popover

Type & motion

--cml-duration-fast--cml-ease-standard--cml-font-field--cml-font-label--cml-motion-scale

This component only

--cml-corner-shape--cml-disabled-opacity--cml-item-divider--cml-item-highlight--cml-select-trigger-shadow

Accessibility

Enter / SpaceOpens the list on the trigger; picks the highlighted option.
↓ / ↑Opens the list, then moves between options.
Home / EndJumps to the first or last option.
A–ZJumps to the next option starting with that letter.
EscCloses the list and returns focus to the trigger.
Was this page helpful? · Edit this page on GitHub