VayuUI

Select

A flexible dropdown select with single, multi, async search, and creatable modes using compound components.

Installation

npx vayu-ui-cli@latest add select

Usage

Select and TextInput share field heights: sm is 36px, md is 44px, and lg is 52px at the default root font size. Set size and disabled on Select.Root. Disabled fields use the same muted appearance as TextInput and cannot open, search, select, or remove chips. Multi-select keeps the same minimum height and grows when chips wrap.

Advanced Select Component

With Async Search, Createable Options & Compound Components

Basic Single Select

Static

Selected: apple

Multi Select

Tags

Selected: ["react","nextjs"]

Async Search

Search users from simulated API

API

Selected: none

Createable Select

Create new options via API

New!

Selected: none

Createable Multi Select

New!

Selected: ["typescript"]

Async + Createable

Search products and create if not found

Combined

Selected: none

Error State

This field is required

Anatomy

import { Select } from 'vayu-ui';

{
  /* Basic Structure */
}
<Select.Root value={value} onValueChange={setValue} label="Label">
  <Select.Trigger placeholder="Choose..." />
  <Select.Content>
    <Select.List>
      <Select.Item value="opt1">Option 1</Select.Item>
      <Select.Item value="opt2">Option 2</Select.Item>
    </Select.List>
    <Select.Loading />
    <Select.SearchHint />
    <Select.AsyncOptions />
    <Select.CreateButton />
    <Select.NotFound>No results</Select.NotFound>
    <Select.Error type="search" />
    <Select.Footer>Footer content</Select.Footer>
  </Select.Content>
</Select.Root>;
  • Select.Root — Root container. Manages selection state, search, and provides context to children.
  • Select.Trigger — Button with search input and multi-value chips. Toggles the dropdown open/close.
  • Select.Content — Portal-based dropdown with automatic positioning above or below the trigger.
  • Select.List — Hybrid renderer for static items and async options. Wraps Select.Item elements.
  • Select.Item — Individual selectable option with check icon for selected state.
  • Select.AsyncOptions — Renders options returned from async search results.
  • Select.CreateButton — Button to create a new option when creatable is enabled.
  • Select.Loading — Loading spinner shown during async search.
  • Select.SearchHint — Hint text shown when search input is shorter than minSearchLength.
  • Select.NotFound — Empty state displayed when no options match the search.
  • Select.Error — Error message for failed search or create operations.
  • Select.Footer — Optional footer content at the bottom of the dropdown.

Accessibility

  • Keyboard Support:
    • Enter / Space — Select the focused option or open the dropdown.
    • ArrowDown — Move focus to the next option. Wraps to first. Opens dropdown if closed.
    • ArrowUp — Move focus to the previous option. Wraps to last. Opens dropdown if closed.
    • Escape — Close the dropdown and return focus to the trigger input.
    • Tab — Move focus between the trigger input and options. Shift+Tab for reverse.
    • Backspace — Remove the last selected value in multi-select mode when search input is empty.
  • ARIA Attributes:
    • role="listbox" on Select.Content.
    • role="option" on each Select.Item and Select.CreateButton.
    • aria-selected on Select.Item reflects the selected state.
    • data-disabled on Select.Item when the option is disabled.
    • Label linked to input via htmlFor and generated id.
  • Focus Behavior:
    • Clicking the trigger focuses the search input and opens the dropdown.
    • Arrow keys move focus between options within the listbox.
    • Closing the dropdown returns focus to the trigger input.
    • Programmatic focus is tracked to prevent unwanted dropdown open on refocus.

Screen reader behavior

When a user focuses the select trigger, the screen reader announces the label and the currently selected value or placeholder. When the dropdown opens, the listbox role is announced along with the number of available options. Each option is announced with its label and selected state via aria-selected. Disabled options are announced as unavailable. When no results are found, the Select.NotFound content is announced. In multi-select mode, selecting or removing values is announced. The Select.Loading and Select.SearchHint states are announced when they appear during async search.

Component Folder Structure

Select/
├── Select.tsx              # Root component with context provider and state management
├── SelectTrigger.tsx       # Trigger with search input and multi-value chips
├── SelectContent.tsx       # Portal-based dropdown with auto-positioning
├── Selectitem.tsx          # Individual selectable option
├── SelectCreateButton.tsx  # Creatable option button with validation
├── SelectOptionList.tsx    # Static and async list renderers
├── SelectStates.tsx        # Loading, NotFound, SearchHint, Error, Footer states
├── types.ts                # TypeScript type definitions
├── index.ts                # Re-exports all components and types
└── README.md               # Component usage reference

Props

Select.Root

PropTypeDefaultDescription
childrenReactNode—Select subcomponents.
valueSelectValue—Controlled value.
defaultValueSelectValue—Uncontrolled initial value.
onValueChange(value: SelectValue) => void—Callback when value changes.
labelstring—Accessible label for the select.
errorstring—Error message displayed below the trigger.
multiplebooleanfalseEnable multi-select mode.
size'sm' | 'md' | 'lg''md'Field size matching TextInput.
disabledbooleanfalseDisable the field and all selection actions.
classNamestring—Additional CSS classes.
onSearch(searchValue: string) => Promise<OptionData[]>—Async search handler. Enables async mode.
searchDebouncenumber300Debounce delay in ms for async search.
minSearchLengthnumber1Minimum characters before triggering search.
isLoadingboolean—External loading state override.
creatablebooleanfalseEnable option creation.
onCreateOption(inputValue: string) => Promise<OptionData | null>—Handler to create a new option.
isCreatingboolean—External creating state override.
createTextstring"Create option"Text for the create button.
validateCreate(inputValue: string) => boolean | string—Validation function. Returns true or error text.

Select.Trigger

PropTypeDefaultDescription
placeholderstring—Placeholder text for the input.
showSearchIconbooleanfalseShow a search icon in the trigger.
size'sm' | 'md' | 'lg'Root sizeOverride the root field size.
classNamestring—Additional CSS classes.

Select.Content

PropTypeDefaultDescription
childrenReactNode—Dropdown content subcomponents.
classNamestring—Additional CSS classes.

Select.Item

PropTypeDefaultDescription
valuestring | number—Unique value. Required.
childrenReactNode—Option label content.
disabledbooleanfalseDisable selection.
classNamestring—Additional CSS classes.

Select.List

PropTypeDefaultDescription
childrenReactNode—Select.Item elements for static options.
classNamestring—Additional CSS classes.

Select.AsyncOptions

PropTypeDefaultDescription
classNamestring—Additional CSS classes.

Select.CreateButton

PropTypeDefaultDescription
childrenReactNode—Custom button label.
classNamestring—Additional CSS classes.

Select.Loading

PropTypeDefaultDescription
childrenReactNode"Searching..."Custom loading text.
classNamestring—Additional CSS classes.

Select.NotFound

PropTypeDefaultDescription
childrenReactNode"No results found"Custom empty text.
classNamestring—Additional CSS classes.

Select.SearchHint

PropTypeDefaultDescription
childrenReactNode—Custom hint text.
classNamestring—Additional CSS classes.

Select.Error

PropTypeDefaultDescription
type'search' | 'create''search'Which error state to display.
childrenReactNode—Custom error content.
classNamestring—Additional CSS classes.

Select.Footer

PropTypeDefaultDescription
childrenReactNode—Footer content.
classNamestring—Additional CSS classes.

On this page