Ink Web

Multi Select

A terminal multi-select input component with keyboard navigation. Navigate with arrow keys or j/k, press Space to toggle selection, and Enter to submit.

Terminal

Installation

npx shadcn@latest add https://raw.githubusercontent.com/cjroth/ink-web/main/packages/ink-ui/registry/multi-select.json
npx shadcn@latest add https://raw.githubusercontent.com/cjroth/ink-web/main/packages/ink-ui/registry/multi-select.json
pnpm dlx shadcn@latest add https://raw.githubusercontent.com/cjroth/ink-web/main/packages/ink-ui/registry/multi-select.json
bunx shadcn@latest add https://raw.githubusercontent.com/cjroth/ink-web/main/packages/ink-ui/registry/multi-select.json

Usage

app/page.tsx
"use client";

import dynamic from "next/dynamic";

const Terminal = dynamic(() => import("./terminal"), {
  ssr: false,
});

export default function Home() {
  return <Terminal />;
}
app/terminal.tsx
"use client";

import { Box, Text } from "ink";
import { InkXterm } from "ink-web";
import { MultiSelect } from '@/components/ui/multi-select'
import "ink-web/css";
import "xterm/css/xterm.css";

const items = [
  { label: 'Apple', value: 'apple' },
  { label: 'Banana', value: 'banana' },
  { label: 'Cherry', value: 'cherry' },
];

export default function Terminal() {
  return (
    <InkXterm focus>
      <Box flexDirection="column">
        <Text>Select fruits:</Text>
        <MultiSelect
          items={items}
          onSubmit={(selected) => console.log('Selected:', selected)}
        />
      </Box>
    </InkXterm>
  )
}

Props

PropTypeDefaultDescription
itemsMultiSelectItem<V>[][]Items to display. Each item must have label and value, optionally key
selectedMultiSelectItem<V>[]-Controlled selection state
defaultSelectedMultiSelectItem<V>[][]Initial selected items (uncontrolled)
focusbooleantrueWhether the component listens to user input
initialIndexnumber0Index of initially-highlighted item
limitnumber-Number of items to display at once (enables scrolling)
indicatorComponentFC<IndicatorProps>-Custom indicator component
checkboxComponentFC<CheckboxProps>-Custom checkbox component
itemComponentFC<ItemProps>-Custom item component
onSelect(item) => void-Called when an item is selected
onUnselect(item) => void-Called when an item is unselected
onSubmit(items) => void-Called when user presses Enter with selected items
onHighlight(item) => void-Called when user highlights an item

Examples

Basic Multi-Select

const items = [
  { label: 'Option 1', value: '1' },
  { label: 'Option 2', value: '2' },
  { label: 'Option 3', value: '3' },
];

<MultiSelect
  items={items}
  onSubmit={(selected) => console.log(selected)}
/>

With Default Selection

const items = [
  { label: 'Red', value: 'red' },
  { label: 'Green', value: 'green' },
  { label: 'Blue', value: 'blue' },
];

<MultiSelect
  items={items}
  defaultSelected={[items[1]]} // Green pre-selected
  onSubmit={handleSubmit}
/>

Controlled Selection

const [selected, setSelected] = useState([]);

<MultiSelect
  items={items}
  selected={selected}
  onSelect={(item) => setSelected([...selected, item])}
  onUnselect={(item) => setSelected(selected.filter(s => s.value !== item.value))}
  onSubmit={handleSubmit}
/>

With Limit (Scrollable)

<MultiSelect
  items={items}
  limit={5}
  onSubmit={handleSubmit}
/>

Keyboard Navigation

  • ↑/k - Move highlight up
  • ↓/j - Move highlight down
  • Space - Toggle selection of highlighted item
  • Enter - Submit selected items