opentui

Build terminal UIs with OpenTUI. Covers Core, frameworks, components, application APIs, testing, extensions, integrations, deployment, and public API lookup.

Install
npx skills add 'https://github.com/anomalyco/opentui/tree/main/packages/web/src/content'
Download bundle ↓
main · ac753b4Scanned 2026-09-15

Contributors

GitHub-linked commit authors for this SKILL.md at the saved revision. Co-authors and history before file renames are not included.

File history ↗

docs/components/select.mdx

docs/components/select.mdxBrowse 89 files
View on GitHub
← Back to SKILL.md

title: Select description: Choose one option from a vertical list

Select

Select shows discrete choices in a vertical list. Use TabSelect for a horizontal set of peer views or Slider for a continuous value.

Focus the select to enable keyboard input.

Availability

FieldAvailability
Package@opentui/core
Core renderableSelectRenderable
React<select> (automatic)
Solid<select> (automatic)
StatusBuilt in

Basic usage

Renderable API

import { SelectRenderable, SelectRenderableEvents, createCliRenderer } from "@opentui/core"

const renderer = await createCliRenderer()

const menu = new SelectRenderable(renderer, {
  id: "menu",
  width: 32,
  height: 6,
  options: [
    { name: "New file", description: "Create a document" },
    { name: "Open file", description: "Browse existing files" },
    { name: "Save", description: "Write current changes" },
  ],
})

menu.on(SelectRenderableEvents.ITEM_SELECTED, (index, option) => {
  console.log("Selected:", option.name)
})

menu.focus()
renderer.root.add(menu)

After pressing Down, the next option is selected:

   New file
   Create a document
 ▶ Open file
   Browse existing files
   Save
   Write current changes

Keyboard navigation

When focused, the select responds to these keys:

KeyAction
Up / kMove selection up
Down / jMove selection down
Shift+Up / Shift+DownFast scroll (5 items)
EnterSelect current item

Events

Item selected

Fires when the user presses Enter on an option:

import { SelectRenderableEvents, type SelectOption } from "@opentui/core"

menu.on(SelectRenderableEvents.ITEM_SELECTED, (index: number, option: SelectOption) => {
  console.log(`Selected index ${index}: ${option.name}`)
})

Selection update

Fires after each movement attempt and each valid setSelectedIndex() call:

menu.on(SelectRenderableEvents.SELECTION_CHANGED, (index: number, option: SelectOption | null) => {
  console.log(`Highlighted: ${option?.name ?? "none"}`)
  // Update a preview pane, for example
})

SELECTION_CHANGED can pass null as the option when the list is empty. ITEM_SELECTED does not fire without an option. The event can fire when the index does not change. This occurs at a movement boundary or when you assign the current index.

Option structure

interface SelectOption {
  name: string // Display text
  description: string // Displays below the name when showDescription is true
  value?: any // Optional value
}

Styling

const styledMenu = new SelectRenderable(renderer, {
  id: "styled-menu",
  width: 40,
  height: 10,
  options: [...],
  backgroundColor: "#1a1a1a",
  selectedBackgroundColor: "#333366",
  selectedTextColor: "#FFFFFF",
  textColor: "#AAAAAA",
  descriptionColor: "#666666",
})

Properties

PropertyTypeDefaultDescription
widthnumber, "auto", or percentage string-Component width
heightnumber, "auto", or percentage string-Component height
optionsSelectOption[][]Available options
selectedIndexnumber0Initially selected index
backgroundColorstring | RGBAtransparentBackground color
textColorstring | RGBA#FFFFFFNormal text color
focusedBackgroundColorstring | RGBA#1a1a1aBackground when focused
focusedTextColorstring | RGBA#FFFFFFText color when focused
selectedBackgroundColorstring | RGBA#334455Selected item background
selectedTextColorstring | RGBA#FFFF00Selected item text color
descriptionColorstring | RGBA#888888Description text color
selectedDescriptionColorstring | RGBA#CCCCCCSelected item description color
showDescriptionbooleantrueShow option descriptions
showScrollIndicatorbooleanfalseShow scroll position indicator
showSelectionIndicatorbooleantrueShow the selection marker and gutter
wrapSelectionbooleanfalseWrap selection at list boundaries
itemSpacingnumber0Spacing between items
fastScrollStepnumber5Items to skip with Shift+Up/Down

Example: file menu

import { BoxRenderable, SelectRenderable, createCliRenderer } from "@opentui/core"

const renderer = await createCliRenderer()

const fileMenu = new SelectRenderable(renderer, {
  width: 25,
  height: 12,
  options: [
    { name: "New", description: "Create new file (Ctrl+N)" },
    { name: "Open...", description: "Open file (Ctrl+O)" },
    { name: "Save", description: "Save file (Ctrl+S)" },
    { name: "Save As...", description: "Save with new name" },
    { name: "---", description: "" }, // Separator (visual only)
    { name: "Exit", description: "Quit application (Ctrl+Q)" },
  ],
})

const menuPanel = new BoxRenderable(renderer, {
  borderStyle: "single",
  borderColor: "#666",
})
menuPanel.add(fileMenu)

fileMenu.focus()
renderer.root.add(menuPanel)

Programmatic control

// Get current selection index
const currentIndex = menu.getSelectedIndex()

// Get currently selected option
const option = menu.getSelectedOption()

// Set selection programmatically
menu.setSelectedIndex(2)

// Navigate programmatically
menu.moveUp() // Move up one item
menu.moveDown() // Move down one item
menu.moveUp(3) // Move up multiple items
menu.selectCurrent() // Trigger selection of current item

// Update options dynamically
menu.options = [
  { name: "New Option 1", description: "First" },
  { name: "New Option 2", description: "Second" },
]

// Toggle display options
menu.showDescription = false
menu.showScrollIndicator = true
menu.showSelectionIndicator = false
menu.wrapSelection = true

Read Interaction, focus, and selection for focus, keyboard, mouse, and event behavior. Use ScrollBox when you need to scroll arbitrary child content instead of options managed by Select.