Select
Select a value from a list of options inside a dropdown menu. This is an alternative to radios when you have a large number of options.
Want to skip the docs? Try our MCP Server
This component is meant to capture user input and should only be used inside forms. If you need an action menu or a generic dropdown menu please use Menu instead.
#
Documentation
#
#
Usage
#
"use client";
import type { ComponentPropsWithoutRef } from "react";
import { Field, Select, SelectContent, SelectTrigger } from "@optiaxiom/react";
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.
SelectSelectTriggerSelectContent
Items must be an array of objects of SelectOption type and at minimum must contain the following two properties:
labelvalue
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";
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";
import {
IconCircle,
IconProgress,
IconProgressCheck,
IconProgressX,
} from "@tabler/icons-react";
export function App() {
return (
<Select
options={[
{
addon: <IconCircle />,
label: "Todo",
value: "Todo",
},
{
addon: <IconProgress />,
label: "In progress",
value: "In progress",
},
{
addon: <IconProgressCheck />,
label: "Done",
value: "Done",
},
{
addon: <IconProgressX />,
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 {
Group,
Select,
SelectContent,
SelectTrigger,
Text,
} from "@optiaxiom/react";
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 (
<Group flexDirection="column" gap="16">
<Select onValueChange={setValue} options={priorities} value={value}>
<SelectTrigger placeholder="Set priority" w="224" />
<SelectContent />
</Select>
<Text fontSize="md">Selected: {value}</Text>
</Group>
);
}Using onChange:
Selected:
"use client";
import {
Group,
Select,
SelectContent,
SelectTrigger,
Text,
} from "@optiaxiom/react";
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 (
<Group flexDirection="column" gap="16">
<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>
</Group>
);
}#
Form usage
#
Use the name prop (and optionally ref and onChange) to integrate Select with forms.
"use client";
import {
Button,
Group,
Select,
SelectContent,
SelectTrigger,
Text,
} from "@optiaxiom/react";
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);
}
}}
>
<Group alignItems="start" flexDirection="column" gap="16">
<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>
</Group>
</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";
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>
);
}#
Trigger
#
By default we use the Button component for the menu trigger which accepts all of the existing button props.
We can also use asChild to render a completely different component. We provide a few built-in buttons:
AngleMenuButton(default)LabelMenuButton
"use client";
import {
LabelMenuButton,
Select,
SelectContent,
SelectTrigger,
} from "@optiaxiom/react";
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 asChild w="224">
<LabelMenuButton label="Priority" />
</SelectTrigger>
<SelectContent />
</Select>
);
}#
Group
#
We can group options using the group property.
"use client";
import { Select, SelectContent, SelectTrigger } from "@optiaxiom/react";
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
#
RadioGroup
Basic control to allow selecting only one item from a set.
#
Props
#
#
Select
#
Doesn't render its own HTML element.
Prop |
|---|
defaultOpenThe initial open state in uncontrolled mode.
Default: |
defaultValueThe initial selected value in uncontrolled mode.
|
disabledWhether the select is disabled.
|
loadingWhether to show loading spinner inside the menu.
|
nameThe name of the inner select element.
|
onBlurHandler for
|
onChangeHandler for
|
onOpenChangeHandler that is called when the open state changes.
|
onValueChangeHandler that is called when the selected value changes.
|
openThe open state in controlled mode.
|
options*The select items/options we want to render.
|
requiredWhether the select value is required.
|
valueThe selected value in controlled mode.
|
#
SelectTrigger
#
Supports all Button props in addition to its own. Renders a <button> element.
Prop |
|---|
addonAfterDisplay content inside the button after
|
addonBeforeDisplay content inside the button before
|
appearanceControl the appearance by selecting between the different button types.
|
asChildChange the default rendered element for the one passed as a child, merging their props and behavior. Read the Composition guide for more details.
|
className
|
iconDisplay an icon before or after the button content or omit
|
iconPositionControl whether to show the icon before or after the button content.
|
loadingWhether to show loading spinner inside the button.
|
placeholderThe placeholder when there is no value.
|
sizeControl the size of the button.
|
squareWhether button should have square shape.
|
#
SelectContent
#
Supports all Box props in addition to its own. Renders a <div> element.
Prop |
|---|
align
Default: |
asChildChange the default rendered element for the one passed as a child, merging their props and behavior. Read the Composition guide for more details.
|
className
|
maxHWhether to restrict the max-height of the content. Content is also restricted by the available height in the screen relative to the trigger.
|
minWWhether to set the min-width to the width of the trigger.
|
side
Default: |
#
Accessibility
#
#
Keyboard interactions
#
Key | Description |
|---|---|
SpaceEnter | When focus is on |
ArrowDown | When focus is on |
ArrowUp | When focus is on |
PageUpPageDown | Moves focus up/down by 10 items at a time. |
HomeEnd | Moves focus to the first/last item. |
Esc | Closes the menu and moves focus back to |
#
Changelog
#
#
1.4.0
#
-
Moved component out of Alpha.
// Before import { Select, SelectContent, SelectTrigger, } from "@optiaxiom/react/unstable"; // After import { Select, SelectContent, SelectTrigger } from "@optiaxiom/react";
#
1.3.0
#
-
Renamed
itemsprop tooptions:// Before <Select items={[]} /> // After <Select options={[]} /> -
Removed
itemToLabel,itemToValue, andisItemDisabledprops 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