Skip to content

Repository files navigation

@lucid-softworks/select

Accessible, unstyled select primitives for React.

import { useState, type ReactElement } from "react";

import { Select } from "@lucid-softworks/select";

export function StatusSelect(): ReactElement {
  const [status, setStatus] = useState("draft");

  return (
    <Select.Root value={status} onValueChange={setStatus}>
      <Select.Label>Status</Select.Label>
      <Select.Trigger>
        <Select.Value placeholder="Choose a status" />
      </Select.Trigger>
      <Select.Content>
        <Select.Option value="draft">Draft</Select.Option>
        <Select.Option value="review">In review</Select.Option>
        <Select.Option value="published">Published</Select.Option>
      </Select.Content>
    </Select.Root>
  );
}

Use defaultValue for uncontrolled selection, or value and onValueChange for controlled selection. Open state can independently be controlled with open and onOpenChange, or initialized with defaultOpen.

Keyboard interaction

The trigger opens with Enter, Space, Arrow Down, or Arrow Up. Within the listbox, arrow keys move through enabled options, Home and End move to the boundaries, typing finds a matching option, and Space or Enter selects it. Escape closes the listbox and restores focus.

Composition and styling

Select.Root, Select.Label, Select.Trigger, Select.Value, Select.Content, and Select.Option are unstyled compound components. Each accepts the standard props for its rendered element, allowing plain CSS, CSS modules, Tailwind, inline styles, or StyleX.

Select.Content uses the native Popover API for top-layer rendering, light dismissal, and browser-managed stacking. Positioning remains presentation owned by the consumer.