Skip to Content
Components
Select ALPHA

Select

Single select combobox widget to allow selection from a fixed set of options.

Documentation

Usage

"use client"; import type { ComponentPropsWithoutRef } from "react"; import { Field } from "@optiaxiom/react"; import { Select, SelectContent, SelectTrigger, } from "@optiaxiom/react/unstable"; export function App({ description, error, label = "Input label", required = false, }: Pick< ComponentPropsWithoutRef<typeof Field>, "description" | "error" | "label" | "required" >) { return ( <Field description={description} error={error} label={label} required={required} > <Select options={[ { label: "No priority", value: "" }, { label: "Urgent", value: "Urgent" }, { label: "High", value: "High" }, { label: "Medium", value: "Medium" }, { label: "Low", value: "Low" }, ]} > <SelectTrigger placeholder="Set priority" w="224" /> <SelectContent /> </Select> </Field> ); }

Anatomy

import { Select, SelectContent, SelectTrigger } from "@optiaxiom/react"; export default () => ( <Select> <SelectTrigger /> <SelectContent /> </Select> );

Structure

Select works with lists of items provided via the options prop. The basic structure includes the main component provider, a trigger, and the content.

  • Select
  • SelectTrigger
  • SelectContent

Items must be an array of objects of SelectOption type and at minimum must contain the following two properties:

  • label
  • value

The trigger can be provided a placeholder to display in case no values have been selected yet (or if an empty value is selected).

"use client"; import { Select, SelectContent, SelectTrigger, } from "@optiaxiom/react/unstable"; export function App() { return ( <Select options={[ { label: "No priority", value: "" }, { label: "Urgent", value: "Urgent" }, { label: "High", value: "High" }, { label: "Medium", value: "Medium" }, { label: "Low", value: "Low" }, ]} > <SelectTrigger placeholder="Set priority" w="224" /> <SelectContent /> </Select> ); }

Content

Select options use the label property as the display text. We can add the addon and description properties to show additional content inside the items.

"use client"; import { Select, SelectContent, SelectTrigger, } from "@optiaxiom/react/unstable"; import { IconCircle, IconProgress, IconProgressCheck, IconProgressX, } from "@tabler/icons-react"; export function App() { return ( <Select options={[ { addon: <IconCircle size={16} />, label: "Todo", value: "Todo", }, { addon: <IconProgress size={16} />, label: "In progress", value: "In progress", }, { addon: <IconProgressCheck size={16} />, label: "Done", value: "Done", }, { addon: <IconProgressX size={16} />, label: "Closed", value: "Closed", }, ]} > <SelectTrigger placeholder="Choose status" w="224" /> <SelectContent /> </Select> ); }

Controlled

Use the value and defaultValue props to toggle between controlled and uncontrolled usage. And combine it with onValueChange / onChange to listen for changes to the state.

Using onValueChange:

Selected:

"use client"; import { Flex, Text } from "@optiaxiom/react"; import { Select, SelectContent, SelectTrigger, } from "@optiaxiom/react/unstable"; import { useState } from "react"; const priorities = [ { label: "No priority", value: "" }, { label: "Urgent", value: "Urgent" }, { label: "High", value: "High" }, { label: "Medium", value: "Medium" }, { label: "Low", value: "Low" }, ]; export function App() { const [value, setValue] = useState(""); return ( <Flex> <Select onValueChange={setValue} options={priorities} value={value}> <SelectTrigger placeholder="Set priority" w="224" /> <SelectContent /> </Select> <Text fontSize="md">Selected: {value}</Text> </Flex> ); }

Using onChange:

Selected:

"use client"; import { Flex, Text } from "@optiaxiom/react"; import { Select, SelectContent, SelectTrigger, } from "@optiaxiom/react/unstable"; import { useState } from "react"; const priorities = [ { label: "No priority", value: "" }, { label: "Urgent", value: "Urgent" }, { label: "High", value: "High" }, { label: "Medium", value: "Medium" }, { label: "Low", value: "Low" }, ]; export function App() { const [value, setValue] = useState(""); return ( <Flex> <Select onChange={(event) => setValue(event.target.value)} options={priorities} value={value} > <SelectTrigger placeholder="Set priority" w="224" /> <SelectContent /> </Select> <Text fontSize="md">Selected: {value}</Text> </Flex> ); }

Form usage

Use the name prop (and optionally ref and onChange) to integrate Select with forms.

Submitted:

"use client"; import { Button, Flex, Text } from "@optiaxiom/react"; import { Select, SelectContent, SelectTrigger, } from "@optiaxiom/react/unstable"; import { useState } from "react"; const priorities = [ { label: "No priority", value: "" }, { label: "Urgent", value: "Urgent" }, { label: "High", value: "High" }, { label: "Medium", value: "Medium" }, { label: "Low", value: "Low" }, ]; export function App() { const [value, setValue] = useState(""); return ( <form onSubmit={(event) => { event.preventDefault(); if (event.target instanceof HTMLFormElement) { setValue(event.target.priority.value); } }} > <Flex alignItems="start"> <Select defaultValue={value} name="priority" options={priorities}> <SelectTrigger placeholder="Set priority" w="224" /> <SelectContent /> </Select> <Button appearance="primary">Submit</Button> <Text fontSize="md">Submitted: {value}</Text> </Flex> </form> ); }

Disabled state

Enable the disabled prop on Select to toggle the disabled state of the input field.

"use client"; import type { ComponentPropsWithoutRef } from "react"; import { Select, SelectContent, SelectTrigger, } from "@optiaxiom/react/unstable"; export function App({ disabled = true, }: Pick<ComponentPropsWithoutRef<typeof Select>, "disabled">) { return ( <Select disabled={disabled} options={[ { label: "No priority", value: "" }, { label: "Urgent", value: "Urgent" }, { label: "High", value: "High" }, { label: "Medium", value: "Medium" }, { label: "Low", value: "Low" }, ]} > <SelectTrigger placeholder="Set priority" w="224" /> <SelectContent /> </Select> ); }

Group

We can group options using the group property.

"use client"; import { Select, SelectContent, SelectTrigger, } from "@optiaxiom/react/unstable"; const groups = { none: { hidden: true, label: "No priority", }, values: { label: "Priorities", separator: true, }, }; export function App() { return ( <Select options={[ { group: groups.none, label: "No priority", value: "", }, { group: groups.values, label: "Urgent", value: "Urgent", }, { group: groups.values, label: "High", value: "High", }, { group: groups.values, label: "Medium", value: "Medium", }, { group: groups.values, label: "Low", value: "Low", }, ]} > <SelectTrigger placeholder="Set priority" w="224" /> <SelectContent /> </Select> ); }

Related

Menu

Multi-purpose combobox widget to allow selection from a dynamic set of options.

DropdownMenu

Display a dropdown menu.

Props

Select

Doesn't render its own HTML element.

Prop

defaultOpen

The initial open state in uncontrolled mode.

false | true

Default: false

defaultValue

The initial selected value in uncontrolled mode.

string

disabled

Whether the select is disabled.

false | true

loading

Whether to show loading spinner inside the menu.

false | true

name

string

onBlur

FocusEventHandler<HTMLElement>

onChange

ChangeEventHandler<HTMLSelectElement>

onOpenChange

Handler that is called when the open state changes.

(open: boolean) => void

onValueChange

Handler that is called when the selected value changes.

(value: string) => void

open

The open state in controlled mode.

false | true

options*

The select items/options we want to render.

readonly SelectOption[] | SelectOption[]

required

false | true

value

The selected value in controlled mode.

string

SelectTrigger

Supports all Button props in addition to its own. Renders a <button> element.

Prop

addonAfter

Display content inside the button after children.

ReactNode

addonBefore

Display content inside the button before children.

ReactNode

appearance

Control the appearance by selecting between the different button types.

"default" | "danger" | "primary" | "subtle" | "danger-outline" | "inverse"

asChild

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read the Composition guide for more details.

false | true

className

string

icon

Display an icon before or after the button content or omit children to only show the icon.

ReactNode

iconPosition

Control whether to show the icon before or after the button content.

"end" | "start"

loading

Whether to show loading spinner inside the button.

false | true

placeholder

string

size

Control the size of the button.

"sm" | "md" | "lg"

square

Whether button should have square shape.

false | true

virtualRef

RefObject<Measurable>

SelectContent

Supports all Box props in addition to its own. Renders a <div> element.

Prop

align

"center" | "end" | "start"

Default: start

asChild

Change the default rendered element for the one passed as a child, merging their props and behavior.

Read the Composition guide for more details.

false | true

className

string

maxH

Whether to restrict the max-height of the content.

Content is also restricted by the available height in the screen relative to the trigger.

"xs" | "sm" | "md" | "lg" | "full"

minW

Whether to set the min-width to the width of the trigger.

"0" | "trigger"

side

"bottom" | "left" | "right" | "top"

Default: bottom

Changelog

1.3.0

  • Renamed items prop to options:

    // Before <Select items={[]} /> // After <Select options={[]} />
  • Removed itemToLabel, itemToValue, and isItemDisabled props in favor of fixed properties on options:

    // Before <Select items={[ { id: "1", name: "Sample", }, ]} itemToLabel={(item) => item.name} itemToValue={(item) => item.id} /> // After <Select options={[ { label: "Sample", value: "1", }, ]} />

0.2.0

  • Added component
Last updated on