or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

form-components.mdindex.mdnavigation-components.mdoverlay-components.mdselection-components.mdutility-components.md
tile.json

selection-components.mddocs/

Selection Components

Advanced selection interfaces including comboboxes, listboxes, radio groups with keyboard navigation, filtering, and full accessibility support.

Capabilities

Combobox

An autocomplete combobox component for searchable selection with keyboard navigation and filtering.

/**
 * Autocomplete combobox component for searchable selection
 * @param props - Combobox properties including value management and behavior options
 */
function Combobox<TValue = string>(
  props: ComboboxProps<TValue>
): JSX.Element;

interface ComboboxProps<TValue = string> extends PolymorphicProps<'div'> {
  /** Current value (controlled) */
  value?: TValue;
  /** Default value (uncontrolled) */
  defaultValue?: TValue;
  /** Value change handler */
  onChange?: (value: TValue) => void;
  /** Function to compare values for equality */
  by?: ByComparator<TValue>;
  /** Whether multiple selection is allowed */
  multiple?: boolean;
  /** Whether combobox is disabled */
  disabled?: boolean;
  /** Whether combobox is in invalid state */
  invalid?: boolean;
  /** Associated form ID */
  form?: string;
  /** Form field name */
  name?: string;
  /** Whether to open on focus immediately */
  immediate?: boolean;
  /** Virtual scrolling configuration for large lists */
  virtual?: {
    options: TValue[];
    disabled?: (value: TValue) => boolean;
  };
  /** Close handler */
  onClose?: () => void;
  /** Render prop providing combobox state */
  children?: React.ReactNode | ((props: ComboboxRenderProps<TValue>) => React.ReactNode);
}

interface ComboboxRenderProps<TValue = string> {
  /** Whether combobox is open */
  open: boolean;
  /** Whether disabled */
  disabled: boolean;
  /** Whether invalid */
  invalid: boolean;
  /** Index of active option */
  activeIndex: number | null;
  /** Active option value */
  activeOption: TValue | null;
  /** Current value */
  value: TValue;
}

ComboboxInput

The input element for the combobox with display value formatting.

/**
 * Input element for the combobox
 * @param props - ComboboxInput properties
 */
function ComboboxInput<TType = string>(
  props: ComboboxInputProps<TType>
): JSX.Element;

interface ComboboxInputProps<TType = string> extends PolymorphicProps<'input'> {
  /** Default input value */
  defaultValue?: TType;
  /** Whether input is disabled */
  disabled?: boolean;
  /** Function to format displayed value */
  displayValue?: (item: TType) => string;
  /** Change handler for input value */
  onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
  /** Whether to auto-focus on mount */
  autoFocus?: boolean;
  /** Render prop providing input state */
  children?: React.ReactNode | ((props: ComboboxInputRenderProps) => React.ReactNode);
}

interface ComboboxInputRenderProps {
  /** Whether combobox is open */
  open: boolean;
  /** Whether disabled */
  disabled: boolean;
  /** Whether invalid */
  invalid: boolean;
  /** Whether being hovered */
  hover: boolean;
  /** Whether has focus */
  focus: boolean;
  /** Whether has autofocus */
  autofocus: boolean;
}

ComboboxButton

Button to toggle the combobox dropdown.

/**
 * Button to toggle the combobox
 * @param props - ComboboxButton properties
 */
function ComboboxButton<TTag extends keyof JSX.IntrinsicElements = 'button'>(
  props: ComboboxButtonProps<TTag>
): JSX.Element;

interface ComboboxButtonProps<TTag extends keyof JSX.IntrinsicElements = 'button'> 
  extends PolymorphicProps<TTag> {
  /** Whether to auto-focus on mount */
  autoFocus?: boolean;
  /** Whether button is disabled */
  disabled?: boolean;
  /** Render prop providing button state */
  children?: React.ReactNode | ((props: ComboboxButtonRenderProps) => React.ReactNode);
}

interface ComboboxButtonRenderProps {
  /** Whether combobox is open */
  open: boolean;
  /** Whether button is active/pressed */
  active: boolean;
  /** Whether disabled */
  disabled: boolean;
  /** Whether invalid */
  invalid: boolean;
  /** Current combobox value */
  value: any;
  /** Whether has focus */
  focus: boolean;
  /** Whether being hovered */
  hover: boolean;
}

ComboboxOptions

Container for combobox options with floating UI positioning.

/**
 * Container for combobox options
 * @param props - ComboboxOptions properties
 */
function ComboboxOptions<TTag extends keyof JSX.IntrinsicElements = 'div'>(
  props: ComboboxOptionsProps<TTag>
): JSX.Element;

interface ComboboxOptionsProps<TTag extends keyof JSX.IntrinsicElements = 'div'> 
  extends PolymorphicProps<TTag> {
  /** Whether to hold focus on options */
  hold?: boolean;  
  /** Floating UI anchor configuration */
  anchor?: AnchorProps;
  /** Whether to render in portal */
  portal?: boolean;
  /** Whether to use modal behavior */
  modal?: boolean;
  /** Whether to use transition */
  transition?: boolean;
  /** Render prop providing options state */
  children?: React.ReactNode | ((props: ComboboxOptionsRenderProps) => React.ReactNode);
}

interface ComboboxOptionsRenderProps {
  /** Whether combobox is open */
  open: boolean;
  /** Current option (in render function) */
  option: any;
}

ComboboxOption

Individual option within the combobox.

/**
 * Individual option within the combobox
 * @param props - ComboboxOption properties
 */
function ComboboxOption<TType = string>(
  props: ComboboxOptionProps<TType>
): JSX.Element;

interface ComboboxOptionProps<TType = string> extends PolymorphicProps<'div'> {
  /** Whether option is disabled */
  disabled?: boolean;
  /** Option value */
  value: TType;
  /** Display order */
  order?: number;
  /** Render prop providing option state */
  children?: React.ReactNode | ((props: ComboboxOptionRenderProps) => React.ReactNode);
}

interface ComboboxOptionRenderProps {
  /** Whether option has focus */
  focus: boolean;
  /** Whether option is active (deprecated, use focus) */
  active: boolean;
  /** Whether option is selected */
  selected: boolean;
  /** Whether option is disabled */
  disabled: boolean;
}

Usage Examples:

import { useState } from "react";
import { 
  Combobox, 
  ComboboxInput, 
  ComboboxButton, 
  ComboboxOptions, 
  ComboboxOption 
} from "@headlessui/react";

const people = [
  { id: 1, name: 'Wade Cooper' },
  { id: 2, name: 'Arlene Mccoy' },
  { id: 3, name: 'Devon Webb' },
];

function ComboboxExample() {
  const [selectedPerson, setSelectedPerson] = useState(people[0]);
  const [query, setQuery] = useState('');

  const filteredPeople = query === ''
    ? people
    : people.filter((person) =>
        person.name.toLowerCase().includes(query.toLowerCase())
      );

  return (
    <Combobox value={selectedPerson} onChange={setSelectedPerson}>
      <div className="relative">
        <ComboboxInput
          className="w-full border border-gray-300 rounded py-2 px-3"
          displayValue={(person) => person?.name}
          onChange={(event) => setQuery(event.target.value)}
        />
        <ComboboxButton className="absolute right-2 top-2">
          <ChevronDownIcon className="w-5 h-5" />
        </ComboboxButton>
      </div>

      <ComboboxOptions className="absolute z-10 mt-1 w-full bg-white border border-gray-300 rounded shadow-lg">
        {filteredPeople.map((person) => (
          <ComboboxOption key={person.id} value={person}>
            {({ focus, selected }) => (
              <div className={`px-3 py-2 cursor-pointer ${
                focus ? 'bg-blue-500 text-white' : 'text-gray-900'
              }`}>
                {person.name}
                {selected && <CheckIcon className="w-5 h-5 ml-2" />}
              </div>
            )}
          </ComboboxOption>
        ))}
      </ComboboxOptions>
    </Combobox>
  );
}

// Multi-select combobox
function MultiSelectExample() {
  const [selectedPeople, setSelectedPeople] = useState([]);
  
  return (
    <Combobox value={selectedPeople} onChange={setSelectedPeople} multiple>
      {/* ... similar structure with multiple selection support ... */}
    </Combobox>
  );
}

Listbox

A listbox selection component with single or multiple selection capabilities.

/**
 * Listbox selection component
 * @param props - Listbox properties including value management and orientation
 */
function Listbox<TType = string>(
  props: ListboxProps<TType>
): JSX.Element;

interface ListboxProps<TType = string> extends PolymorphicProps<'div'> {
  /** Current value */
  value?: TType;
  /** Default value */
  defaultValue?: TType;
  /** Value change handler */
  onChange?: (value: TType) => void;
  /** Function to compare values for equality */
  by?: ByComparator<TType>;
  /** Whether listbox is disabled */
  disabled?: boolean;
  /** Whether listbox is invalid */
  invalid?: boolean;
  /** Whether horizontal orientation */
  horizontal?: boolean;
  /** Associated form ID */
  form?: string;
  /** Form field name */
  name?: string;
  /** Whether multiple selection is allowed */
  multiple?: boolean;
  /** Render prop providing listbox state */
  children?: React.ReactNode | ((props: ListboxRenderProps<TType>) => React.ReactNode);
}

interface ListboxRenderProps<TType = string> {
  /** Whether listbox is open */
  open: boolean;
  /** Whether disabled */
  disabled: boolean;
  /** Whether invalid */
  invalid: boolean;
  /** Current value */
  value: TType;
}

ListboxButton

Button to toggle the listbox dropdown.

/**
 * Button to toggle the listbox
 * @param props - ListboxButton properties
 */
function ListboxButton<TTag extends keyof JSX.IntrinsicElements = 'button'>(
  props: ListboxButtonProps<TTag>
): JSX.Element;

interface ListboxButtonProps<TTag extends keyof JSX.IntrinsicElements = 'button'> 
  extends PolymorphicProps<TTag> {
  /** Whether button is disabled */
  disabled?: boolean;
  /** Whether to auto-focus on mount */
  autoFocus?: boolean;
  /** Render prop providing button state */
  children?: React.ReactNode | ((props: ListboxButtonRenderProps) => React.ReactNode);
}

interface ListboxButtonRenderProps {
  /** Whether listbox is open */
  open: boolean;
  /** Whether button is active */
  active: boolean;
  /** Whether being hovered */
  hover: boolean;
  /** Whether has focus */
  focus: boolean;
  /** Whether disabled */
  disabled: boolean;
  /** Whether has autofocus */
  autofocus: boolean;
}

ListboxOptions

Container for listbox options.

/**
 * Container for listbox options
 * @param props - ListboxOptions properties
 */
function ListboxOptions<TTag extends keyof JSX.IntrinsicElements = 'div'>(
  props: ListboxOptionsProps<TTag>
): JSX.Element;

interface ListboxOptionsProps<TTag extends keyof JSX.IntrinsicElements = 'div'> 
  extends PolymorphicProps<TTag> {
  /** Whether to hold focus on options */
  hold?: boolean;
  /** Floating UI anchor configuration */
  anchor?: AnchorProps;
  /** Whether to render in portal */
  portal?: boolean;
  /** Whether to use modal behavior */
  modal?: boolean;
  /** Whether to use transition */
  transition?: boolean;
  /** Render prop providing options state */
  children?: React.ReactNode | ((props: ListboxOptionsRenderProps) => React.ReactNode);
}

interface ListboxOptionsRenderProps {
  /** Whether listbox is open */
  open: boolean;
}

ListboxOption

Individual option within the listbox.

/**
 * Individual option within the listbox
 * @param props - ListboxOption properties
 */
function ListboxOption<TType = string>(
  props: ListboxOptionProps<TType>
): JSX.Element;

interface ListboxOptionProps<TType = string> extends PolymorphicProps<'div'> {
  /** Whether option is disabled */
  disabled?: boolean;
  /** Option value */
  value: TType;
  /** Display order */
  order?: number;
  /** Render prop providing option state */
  children?: React.ReactNode | ((props: ListboxOptionRenderProps) => React.ReactNode);
}

interface ListboxOptionRenderProps {
  /** Whether option has focus */
  focus: boolean;
  /** Whether option is active (deprecated, use focus) */
  active: boolean;
  /** Whether option is selected */
  selected: boolean;
  /** Whether option is disabled */
  disabled: boolean;
}

Usage Examples:

import { useState } from "react";
import { 
  Listbox, 
  ListboxButton, 
  ListboxOptions, 
  ListboxOption 
} from "@headlessui/react";

const options = ['Option 1', 'Option 2', 'Option 3'];

function ListboxExample() {
  const [selected, setSelected] = useState(options[0]);

  return (
    <Listbox value={selected} onChange={setSelected}>
      <div className="relative">
        <ListboxButton className="w-full border border-gray-300 rounded py-2 px-3 text-left">
          {selected}
          <ChevronDownIcon className="w-5 h-5 float-right" />
        </ListboxButton>
        
        <ListboxOptions className="absolute z-10 mt-1 w-full bg-white border border-gray-300 rounded shadow-lg">
          {options.map((option) => (
            <ListboxOption key={option} value={option}>
              {({ focus, selected }) => (
                <div className={`px-3 py-2 cursor-pointer ${
                  focus ? 'bg-blue-500 text-white' : 'text-gray-900'
                }`}>
                  {option}
                  {selected && <CheckIcon className="w-5 h-5 ml-2" />}
                </div>
              )}
            </ListboxOption>
          ))}
        </ListboxOptions>
      </div>
    </Listbox>
  );
}

RadioGroup

A radio group component for single selection from multiple options.

/**
 * Radio group for single selection
 * @param props - RadioGroup properties
 */
function RadioGroup<TValue = string>(
  props: RadioGroupProps<TValue>
): JSX.Element;

interface RadioGroupProps<TValue = string> extends PolymorphicProps<'div'> {
  /** Current value */
  value?: TValue;
  /** Default value */
  defaultValue?: TValue;
  /** Value change handler */
  onChange?: (value: TValue) => void;
  /** Function to compare values for equality */
  by?: ByComparator<TValue>;
  /** Whether radio group is disabled */
  disabled?: boolean;
  /** Associated form ID */
  form?: string;
  /** Form field name */
  name?: string;
  /** Render prop providing radio group state */
  children?: React.ReactNode | ((props: RadioGroupRenderProps<TValue>) => React.ReactNode);
}

interface RadioGroupRenderProps<TValue = string> {
  /** Current value */
  value: TValue;
  /** Whether disabled */
  disabled: boolean;
}

RadioGroupOption

Individual radio option within the group.

/**
 * Individual radio option
 * @param props - RadioGroupOption properties
 */
function RadioGroupOption<TValue = string>(
  props: RadioGroupOptionProps<TValue>
): JSX.Element;

interface RadioGroupOptionProps<TValue = string> extends PolymorphicProps<'div'> {
  /** Option value */
  value: TValue;
  /** Whether option is disabled */
  disabled?: boolean;
  /** Display order */
  order?: number;
  /** Render prop providing option state */
  children?: React.ReactNode | ((props: RadioGroupOptionRenderProps) => React.ReactNode);
}

interface RadioGroupOptionRenderProps {
  /** Whether option is checked */
  checked: boolean;  
  /** Whether option is active/pressed */
  active: boolean;
  /** Whether being hovered */
  hover: boolean;
  /** Whether has focus */
  focus: boolean;
  /** Whether disabled */
  disabled: boolean;
}

Radio

Individual radio input component (can be used independently).

/**
 * Individual radio input component
 * @param props - Radio properties
 */
function Radio<TValue = string>(
  props: RadioProps<TValue>
): JSX.Element;

interface RadioProps<TValue = string> extends PolymorphicProps<'input'> {
  /** Radio value */
  value: TValue;
  /** Whether radio is disabled */
  disabled?: boolean;
  /** Whether to auto-focus on mount */
  autoFocus?: boolean;
  /** Associated form ID */
  form?: string;
  /** Form field name */
  name?: string;
  /** Change handler */
  onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
  /** Tab index */
  tabIndex?: number;
  /** Render prop providing radio state */
  children?: React.ReactNode | ((props: RadioRenderProps) => React.ReactNode);
}

interface RadioRenderProps {
  /** Whether radio is checked */
  checked: boolean;
  /** Whether currently changing state */
  changing: boolean;
  /** Whether has focus */
  focus: boolean;
  /** Whether being pressed */
  active: boolean;
  /** Whether being hovered */
  hover: boolean;
  /** Whether has autofocus */
  autofocus: boolean;
  /** Whether disabled */
  disabled: boolean;
}

Usage Examples:

import { useState } from "react";
import { RadioGroup, RadioGroupOption, Radio } from "@headlessui/react";

const plans = [
  { name: 'Startup', price: '$29/month' },
  { name: 'Business', price: '$99/month' },
  { name: 'Enterprise', price: '$249/month' },
];

function RadioGroupExample() {
  const [selected, setSelected] = useState(plans[0]);

  return (
    <RadioGroup value={selected} onChange={setSelected}>
      <div className="space-y-2">
        {plans.map((plan) => (
          <RadioGroupOption key={plan.name} value={plan}>
            {({ checked }) => (
              <div className={`${checked ? 'bg-blue-500 text-white' : 'bg-white text-gray-900'}
                              relative rounded-lg px-5 py-4 cursor-pointer border border-gray-300 
                              focus:outline-none focus:ring-2 focus:ring-blue-500`}>
                <div className="flex items-center justify-between">
                  <div>
                    <p className="font-medium">{plan.name}</p>
                    <p className="text-sm">{plan.price}</p>
                  </div>
                  {checked && <CheckIcon className="w-6 h-6" />}
                </div>
              </div>
            )}
          </RadioGroupOption>
        ))}
      </div>
    </RadioGroup>
  );
}

// Standalone radio buttons
function StandaloneRadioExample() {
  return (
    <form>
      <div className="space-y-2">
        <label className="flex items-center">
          <Radio name="plan" value="startup" />
          <span className="ml-2">Startup Plan</span>
        </label>
        <label className="flex items-center">
          <Radio name="plan" value="business" />
          <span className="ml-2">Business Plan</span>
        </label>
      </div>
    </form>
  );
}

Common Types

// Value comparison function type
type ByComparator<T> = 
  | ((a: T, z: T) => boolean)
  | keyof T
  | null;

// Floating UI anchor configuration
interface AnchorProps {
  to?: string;
  gap?: number;
  offset?: number;
  padding?: number;
}

// Common option render props
interface BaseOptionRenderProps {
  focus: boolean;
  active: boolean; // Deprecated in favor of focus
  selected: boolean;
  disabled: boolean;
}

// Common selection component render props
interface BaseSelectionRenderProps<TValue = any> {
  open: boolean;
  disabled: boolean;
  invalid?: boolean;
  value: TValue;
}