Select
A select component built on Radix UI's Select primitive that allows users to choose a single value from a dropdown list of options. Features keyboard navigation, accessibility, and customizable styling.
Installation
pnpm add @helgadigitals/vera-uinpm install @helgadigitals/vera-uiyarn add @helgadigitals/vera-uiUsage
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@helgadigitals/vera-ui"export default function Example() {return ( <Select> <SelectTrigger className="w-[180px]"> <SelectValue placeholder="Select a fruit" /> </SelectTrigger> <SelectContent> <SelectItem value="apple">Apple</SelectItem> <SelectItem value="banana">Banana</SelectItem> <SelectItem value="orange">Orange</SelectItem> </SelectContent> </Select>)}Examples
With Groups
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue,SelectGroup,SelectLabel } from "@helgadigitals/vera-ui"export default function GroupedExample() {return ( <Select> <SelectTrigger className="w-[180px]"> <SelectValue placeholder="Select a food" /> </SelectTrigger> <SelectContent> <SelectGroup> <SelectLabel>Fruits</SelectLabel> <SelectItem value="apple">Apple</SelectItem> <SelectItem value="banana">Banana</SelectItem> <SelectItem value="orange">Orange</SelectItem> </SelectGroup> <SelectGroup> <SelectLabel>Vegetables</SelectLabel> <SelectItem value="carrot">Carrot</SelectItem> <SelectItem value="broccoli">Broccoli</SelectItem> <SelectItem value="spinach">Spinach</SelectItem> </SelectGroup> </SelectContent> </Select>)}Controlled Select
import { useState } from "react"import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@helgadigitals/vera-ui"export default function ControlledExample() {const [selectedValue, setSelectedValue] = useState("")return ( <div className="space-y-4"> <div className="space-y-2"> <label className="text-sm font-medium">Choose a country</label> <Select value={selectedValue} onValueChange={setSelectedValue}> <SelectTrigger className="w-[200px]"> <SelectValue placeholder="Select country" /> </SelectTrigger> <SelectContent> <SelectItem value="us">United States</SelectItem> <SelectItem value="ca">Canada</SelectItem> <SelectItem value="uk">United Kingdom</SelectItem> <SelectItem value="au">Australia</SelectItem> </SelectContent> </Select> </div> {selectedValue && ( <p className="text-sm text-muted-foreground"> Selected: {selectedValue} </p> )} </div>)}With Groups and Labels
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue,SelectGroup,SelectLabel,SelectSeparator} from "@helgadigitals/vera-ui"export default function GroupedExample() {return ( <div className="space-y-2"> <label className="text-sm font-medium">Choose a programming language</label> <Select> <SelectTrigger className="w-[250px]"> <SelectValue placeholder="Select language" /> </SelectTrigger> <SelectContent> <SelectGroup> <SelectLabel>Frontend</SelectLabel> <SelectItem value="javascript">JavaScript</SelectItem> <SelectItem value="typescript">TypeScript</SelectItem> <SelectItem value="css">CSS</SelectItem> </SelectGroup> <SelectSeparator /> <SelectGroup> <SelectLabel>Backend</SelectLabel> <SelectItem value="python">Python</SelectItem> <SelectItem value="java">Java</SelectItem> <SelectItem value="go">Go</SelectItem> <SelectItem value="rust">Rust</SelectItem> </SelectGroup> <SelectSeparator /> <SelectGroup> <SelectLabel>Mobile</SelectLabel> <SelectItem value="swift">Swift</SelectItem> <SelectItem value="kotlin">Kotlin</SelectItem> <SelectItem value="dart">Dart</SelectItem> </SelectGroup> </SelectContent> </Select> </div>)}Different Sizes
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@helgadigitals/vera-ui"export default function SizesExample() {return ( <div className="space-y-4"> <div className="space-y-2"> <label className="text-sm font-medium">Small Select</label> <Select> <SelectTrigger size="sm" className="w-[150px]"> <SelectValue placeholder="Small" /> </SelectTrigger> <SelectContent> <SelectItem value="option1">Option 1</SelectItem> <SelectItem value="option2">Option 2</SelectItem> </SelectContent> </Select> </div> <div className="space-y-2"> <label className="text-sm font-medium">Default Select</label> <Select> <SelectTrigger className="w-[180px]"> <SelectValue placeholder="Default" /> </SelectTrigger> <SelectContent> <SelectItem value="option1">Option 1</SelectItem> <SelectItem value="option2">Option 2</SelectItem> </SelectContent> </Select> </div> </div>)}Disabled States
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@helgadigitals/vera-ui"export default function DisabledExample() {return ( <div className="space-y-6"> {/* Disabled select */} <div className="space-y-2"> <label className="text-sm font-medium">Disabled Select</label> <Select disabled> <SelectTrigger className="w-[200px]"> <SelectValue placeholder="Disabled select" /> </SelectTrigger> <SelectContent> <SelectItem value="option1">Option 1</SelectItem> <SelectItem value="option2">Option 2</SelectItem> </SelectContent> </Select> </div> {/* Individual disabled items */} <div className="space-y-2"> <label className="text-sm font-medium">With Disabled Items</label> <Select> <SelectTrigger className="w-[200px]"> <SelectValue placeholder="Select option" /> </SelectTrigger> <SelectContent> <SelectItem value="available1">Available Option 1</SelectItem> <SelectItem value="disabled" disabled> Disabled Option </SelectItem> <SelectItem value="available2">Available Option 2</SelectItem> </SelectContent> </Select> </div> </div>)}With Icons
import { User, Mail, Phone, MessageSquare } from "lucide-react"import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@helgadigitals/vera-ui"export default function WithIconsExample() {return ( <div className="space-y-2"> <label className="text-sm font-medium">Contact method</label> <Select> <SelectTrigger className="w-[220px]"> <SelectValue placeholder="Choose contact method" /> </SelectTrigger> <SelectContent> <SelectItem value="email"> <Mail className="mr-2 h-4 w-4" /> Email </SelectItem> <SelectItem value="phone"> <Phone className="mr-2 h-4 w-4" /> Phone </SelectItem> <SelectItem value="message"> <MessageSquare className="mr-2 h-4 w-4" /> Message </SelectItem> <SelectItem value="in-person"> <User className="mr-2 h-4 w-4" /> In Person </SelectItem> </SelectContent> </Select> </div>)}Form Integration
Current Values:
{
"country": "none",
"theme": "system"
}import { useForm, Controller } from "react-hook-form"import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue,Button } from "@helgadigitals/vera-ui"export default function FormExample() {const { control, handleSubmit, formState: { errors } } = useForm()const onSubmit = (data) => { console.log(data)}return ( <form onSubmit={handleSubmit(onSubmit)} className="space-y-6"> <div className="space-y-2"> <label className="text-sm font-medium">Country *</label> <Controller name="country" control={control} rules={{ required: "Please select a country" }} render={({ field }) => ( <Select onValueChange={field.onChange} value={field.value || ""}> <SelectTrigger className="w-full"> <SelectValue placeholder="Select your country" /> </SelectTrigger> <SelectContent> <SelectItem value="us">United States</SelectItem> <SelectItem value="ca">Canada</SelectItem> <SelectItem value="uk">United Kingdom</SelectItem> <SelectItem value="au">Australia</SelectItem> <SelectItem value="de">Germany</SelectItem> <SelectItem value="fr">France</SelectItem> </SelectContent> </Select> )} /> {errors.country && ( <p className="text-sm text-destructive"> {errors.country.message} </p> )} </div> <div className="space-y-2"> <label className="text-sm font-medium">Theme preference</label> <Controller name="theme" control={control} defaultValue="system" render={({ field }) => ( <Select onValueChange={field.onChange} value={field.value}> <SelectTrigger className="w-full"> <SelectValue /> </SelectTrigger> <SelectContent> <SelectItem value="light">Light</SelectItem> <SelectItem value="dark">Dark</SelectItem> <SelectItem value="system">System</SelectItem> </SelectContent> </Select> )} /> </div> <Button type="submit">Submit</Button> </form>)}Long Lists with Search
Type to search through 193 countries
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@helgadigitals/vera-ui"const countries = [{ value: "af", label: "Afghanistan" },{ value: "al", label: "Albania" },{ value: "dz", label: "Algeria" },{ value: "ad", label: "Andorra" },{ value: "ao", label: "Angola" },// ... many more countries{ value: "us", label: "United States" },{ value: "uy", label: "Uruguay" },{ value: "uz", label: "Uzbekistan" },{ value: "vu", label: "Vanuatu" },{ value: "ve", label: "Venezuela" },{ value: "vn", label: "Vietnam" },{ value: "ye", label: "Yemen" },{ value: "zm", label: "Zambia" },{ value: "zw", label: "Zimbabwe" },]export default function LongListExample() {return ( <div className="space-y-2"> <label className="text-sm font-medium">Country</label> <Select> <SelectTrigger className="w-[250px]"> <SelectValue placeholder="Select a country" /> </SelectTrigger> <SelectContent> {countries.map((country) => ( <SelectItem key={country.value} value={country.value}> {country.label} </SelectItem> ))} </SelectContent> </Select> </div>)}API Reference
Select
Root component that provides context for all other select components.
Prop
Type
SelectTrigger
The button that triggers the select dropdown.
Prop
Type
SelectContent
The dropdown content that contains the select options.
Prop
Type
SelectValue
Displays the selected value or placeholder.
Prop
Type
SelectItem
An option in the select dropdown.
Prop
Type
SelectGroup
Groups related select items together.
Prop
Type
SelectLabel
A label for a group of select items.
Prop
Type
SelectSeparator
A visual separator between select items or groups.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Additional CSS classes |
Accessibility
The Select component follows WAI-ARIA guidelines:
- Keyboard Navigation:
- Space or Enter opens the dropdown
- Arrow keys navigate between options
- Type to search for options
- Escape closes the dropdown
- Screen Readers: Proper ARIA attributes and announcements
- Focus Management: Focus is properly managed between trigger and content
- Selection: Selected value is properly announced to screen readers
Search Functionality: Users can type while the dropdown is open to quickly find options. The component will automatically highlight matching items.
Data Attributes
The following data attributes are automatically applied and can be used for styling:
SelectTrigger
| Attribute | Values | Description |
|---|---|---|
data-state | "open" | "closed" | The open state of the select |
data-disabled | Present when disabled | Applied when the select is disabled |
data-placeholder | Present when placeholder is shown | Applied when no value is selected |
SelectItem
| Attribute | Values | Description |
|---|---|---|
data-state | "checked" | "unchecked" | Whether the item is selected |
data-highlighted | Present when highlighted | Applied when the item is highlighted |
data-disabled | Present when disabled | Applied when the item is disabled |
Best Practices
Provide Clear Labels
Always include descriptive labels for your select components:
// Good: Clear label
<div className="space-y-2">
<label htmlFor="country-select" className="text-sm font-medium">
Country
</label>
<Select>
<SelectTrigger id="country-select">
<SelectValue placeholder="Select your country" />
</SelectTrigger>
{/* ... */}
</Select>
</div>Use Appropriate Placeholder Text
Placeholder text should guide users about what to select:
// Good: Descriptive placeholder
<SelectValue placeholder="Choose your preferred language" />
// Avoid: Generic placeholder
<SelectValue placeholder="Select..." />Group Related Options
Use groups and labels to organize related options:
<SelectContent>
<SelectGroup>
<SelectLabel>Popular Frameworks</SelectLabel>
<SelectItem value="react">React</SelectItem>
<SelectItem value="vue">Vue</SelectItem>
</SelectGroup>
<SelectSeparator />
<SelectGroup>
<SelectLabel>Other Options</SelectLabel>
<SelectItem value="angular">Angular</SelectItem>
<SelectItem value="svelte">Svelte</SelectItem>
</SelectGroup>
</SelectContent>Styling
The Select component supports custom styling through CSS classes:
<Select>
<SelectTrigger className="w-full border-blue-300 focus:border-blue-500">
<SelectValue />
</SelectTrigger>
<SelectContent className="bg-blue-50">
<SelectItem
value="option1"
className="hover:bg-blue-100 focus:bg-blue-100"
>
Option 1
</SelectItem>
</SelectContent>
</Select>Radio Group
A radio group is a set of checkable buttons where only one can be checked at a time. Built on Radix UI's RadioGroup primitive, it provides accessible single-choice selection with keyboard navigation.
Switch
A switch component built on Radix UI's Switch primitive that allows users to toggle between on and off states. Perfect for boolean settings, preferences, and feature toggles.