Installation

Barrel

// code example

Granular

// code example

Usage


export default function Example() {
  const [value, setValue] = useState("apple");

  return (
    <Select
      label="Favorite Fruit"
      value={value}
      onValueChange={(v) => setValue(v ?? "apple")}
      items={{ apple: "Apple", banana: "Banana", cherry: "Cherry" }}
/>
  );
}

Examples

Basic

A select with a visible label. When you provide the label prop, the select automatically renders inside a Field wrapper with the label displayed above it.

Sizes

Use the <code class="rounded bg-kumo-control px-1 py-0.5 text-sm">size</code> prop
to match Input sizing (xs, sm, base, lg).

Without Visible Label

When a visible label isn't needed (e.g., in compact UIs or when context is clear),
use `aria-label` for accessibility.

With Description and Error

Select integrates with the Field wrapper to show description text and validation errors.

Placeholder

Use the <code class="rounded bg-kumo-control px-1 py-0.5 text-sm">placeholder</code> prop
to show text when no value is selected. When using <code class="rounded bg-kumo-control px-1 py-0.5 text-sm">renderValue</code> to
customize the display of selected values, the placeholder is shown instead of
calling <code class="rounded bg-kumo-control px-1 py-0.5 text-sm">renderValue</code> when the value is <code class="rounded bg-kumo-control px-1 py-0.5 text-sm">null</code>.
<Select
  placeholder="Select a user..."
  value={user}
  renderValue={(user) => user.name} // Only called when user is not null
/>

Label with Tooltip

Add a tooltip icon next to the label for additional context using <code
  class="rounded bg-kumo-control px-1 py-0.5 text-sm">labelTooltip</code>.

Custom Rendering

Use <code class="rounded bg-kumo-control px-1 py-0.5 text-sm">renderValue</code> to customize how the selected value
appears in the trigger button. This is useful when working with complex object
data structures instead of simple string values.

The renderValue function is only called when a value is selected. Use placeholder to define what to show when no value is selected.

Select compares value with items to find which one is selected. For object items, it will compare if the object is the same reference not by value by default. If you want to compare object items by value, you can use isItemEqualToValue prop.

<Select
  className="w-[200px]"
  placeholder="Select a language..."
  renderValue={(v) => (
    <span>
      {v.emoji} {v.label}
    </span>
  )}
  value={value}
  onValueChange={(v) => setValue(v)}
  // Provides custom comparison logic
  isItemEqualToValue={(item, value) => item.value === value.value}
>
  {languages.map((language) => (
    <Select.Option key={language.value} value={language}>
      {language.emoji} {language.label}
    </Select.Option>
  ))}
</Select>

Loading

A select component with loading state. The loading state is passed to
the component via the <code
  class="rounded bg-kumo-control px-1 py-0.5 text-sm">loading</code> prop.

Multiple Selection

Enable multiple selection with the <code class="rounded bg-kumo-control px-1 py-0.5 text-sm">multiple</code> prop.
The value becomes an array of selected items. Use <code class="rounded bg-kumo-control px-1 py-0.5 text-sm">placeholder</code> for the empty state
and <code class="rounded bg-kumo-control px-1 py-0.5 text-sm">renderValue</code> to customize how selections are displayed.
<Select
  multiple
  placeholder="Select columns..."
  value={selectedColumns}
  renderValue={(columns) => columns.join(", ")}
  onValueChange={setSelectedColumns}
>
  <Select.Option value="name">Name</Select.Option>
  <Select.Option value="email">Email</Select.Option>
</Select>

More Example

Disabled Options

Options can be disabled with the <code class="rounded bg-kumo-control px-1 py-0.5 text-sm">disabled</code> prop.
Disabled options are greyed out and cannot be selected.

Disabled Items (via items prop)

The <code class="rounded bg-kumo-control px-1 py-0.5 text-sm">items</code> object-map prop
accepts descriptor objects with <code class="rounded bg-kumo-control px-1 py-0.5 text-sm">disabled</code> alongside
plain string values.

Grouped Options

Use <code class="rounded bg-kumo-control px-1 py-0.5 text-sm">Select.Group</code>, 
<code class="rounded bg-kumo-control px-1 py-0.5 text-sm">Select.GroupLabel</code>, and 
<code class="rounded bg-kumo-control px-1 py-0.5 text-sm">Select.Separator</code> to
organize options under labeled headers with visual dividers.

Groups with Disabled Options

Combine groups, separators, and disabled options with info tooltips to
clearly separate available and unavailable choices.

Long List (Scrolling Test)

A select component with many options to test popup scrolling behavior.
The popup should scroll smoothly without bounce/overscroll issues.

API Reference

Select

Props table: Select

Select.Option

Props table: Select.Option

Select.Group

Groups related options together with an accessible role="group". Use with Select.GroupLabel to provide a visible heading.

Select.GroupLabel

A visible heading for a Select.Group. Automatically associated with its parent group for accessibility.

Select.Separator

A visual divider line between option groups. Renders with role="separator".