giggles

Select

API reference for the Select component

A single-select list.

Works in controlled or uncontrolled mode. Pass value and onChange to own the selection state yourself; omit them to let the component manage it internally. Use onHighlight to observe cursor movement without taking ownership of state.

By default, onChange fires when Enter is pressed. Set immediate to fire onChange on every highlight change instead — useful for previewing the selected option as you browse. Use onSubmit to handle the final confirmation separately.

The direction prop controls both layout and navigation keys. Vertical uses j/k/Up/Down, horizontal uses h/l/Left/Right.

Basic Usage
import { Select } from 'giggles/ui';

const languages = [
  { label: 'TypeScript', value: 'ts' },
  { label: 'Rust', value: 'rs' },
  { label: 'Go', value: 'go' },
];

// uncontrolled — no useState needed
function LanguagePicker() {
  return <Select options={languages} onSubmit={(lang) => console.log(lang)} />;
}

// controlled — caller owns selection state
function ControlledLanguagePicker() {
  const [lang, setLang] = useState('ts');
  return <Select options={languages} value={lang} onChange={setLang} />;
}

Option values must be unique. Duplicate values will throw a GigglesError. Use primitive types (strings, numbers) for option values — object references are compared with ===.

API Reference

Select

Prop

Type

Keybindings

KeyAction
j / Highlight next (vertical)
k / Highlight previous (vertical)
l / Highlight next (horizontal)
h / Highlight previous (horizontal)
EnterConfirm selection
Tab / Shift+TabMove to next/previous component

SelectOption

Prop

Type

SelectRenderProps

Prop

Type

Examples

Immediate mode with preview

Immediate Mode with Preview
function FileTypePicker() {
  const [type, setType] = useState('json');
  const [preview, setPreview] = useState('');

  return (
    <Box flexDirection="row" gap={2}>
      <Select
        options={fileTypes}
        value={type}
        onChange={setType}
        onHighlight={(v) => setPreview(loadPreview(v))}
        immediate
      />
      <Text>{preview}</Text>
    </Box>
  );
}

Custom render

Custom Render
<Select
  options={options}
  value={selected}
  onChange={setSelected}
  render={({ option, highlighted, selected }) => (
    <Text color={highlighted ? 'cyan' : 'white'} bold={selected}>
      {highlighted ? '→' : ' '} {option.label}
    </Text>
  )}
/>

On this page