TabSelect

Horizontal tab-based selection component with descriptions and scroll support. The component must be focused to receive keyboard input.

Basic Usage

Renderable API

import { TabSelectRenderable, TabSelectRenderableEvents, createCliRenderer } from "@opentui/core"

const renderer = await createCliRenderer()

const tabs = new TabSelectRenderable(renderer, {
  id: "tabs",
  width: 60,
  options: [
    { name: "Home", description: "Dashboard and overview" },
    { name: "Files", description: "File management" },
    { name: "Settings", description: "Application settings" },
  ],
  tabWidth: 20,
})

tabs.on(TabSelectRenderableEvents.ITEM_SELECTED, (index, option) => {
  console.log("Tab selected:", option.name)
})

tabs.focus()
renderer.root.add(tabs)

Construct API

import { TabSelect, createCliRenderer } from "@opentui/core"

const renderer = await createCliRenderer()

const tabs = TabSelect({
  width: 60,
  tabWidth: 15,
  options: [
    { name: "Tab 1", description: "First tab" },
    { name: "Tab 2", description: "Second tab" },
    { name: "Tab 3", description: "Third tab" },
  ],
})

tabs.focus()
renderer.root.add(tabs)

Keyboard Navigation

When focused, the tab select responds to these keys:

KeyAction
Left / [Move to previous tab
Right / ]Move to next tab
EnterSelect current tab

Events

Item Selected

Emitted when the user presses Enter on a tab:

import { TabSelectRenderableEvents, type TabSelectOption } from "@opentui/core"

tabs.on(TabSelectRenderableEvents.ITEM_SELECTED, (index: number, option: TabSelectOption) => {
  console.log(`Selected tab ${index}: ${option.name}`)
  // Switch to the corresponding panel
})

Selection Changed

Emitted when the highlighted tab changes:

import { TabSelectRenderableEvents, type TabSelectOption } from "@opentui/core"

tabs.on(TabSelectRenderableEvents.SELECTION_CHANGED, (index: number, option: TabSelectOption) => {
  console.log(`Hovering: ${option.name}`)
})

Properties

PropertyTypeDefaultDescription
widthnumber-Total component width
optionsTabSelectOption[][]Available tabs
tabWidthnumber20Width of each tab
backgroundColorstring | RGBAtransparentBackground color
textColorstring | RGBA#FFFFFFNormal tab text
focusedBackgroundColorstring | RGBA#1a1a1aBackground color when focused
focusedTextColorstring | RGBA#FFFFFFText color when focused
selectedBackgroundColorstring | RGBA#334455Selected tab background
selectedTextColorstring | RGBA#FFFF00Selected tab text
selectedDescriptionColorstring | RGBA#CCCCCCDescription text color
showScrollArrowsbooleantrueShow scroll indicators
showDescriptionbooleantrueShow tab descriptions
showUnderlinebooleantrueShow underline on selected tab
wrapSelectionbooleanfalseWrap around when navigating
keyBindingsTabSelectKeyBinding[]-Custom key bindings
keyAliasMapKeyAliasMap-Key alias mappings

Example: Tabbed Interface

import { Box, Text, TabSelect, createCliRenderer } from "@opentui/core"

const renderer = await createCliRenderer()

// Create content panels
const panels = {
  home: Box({ padding: 1 }, Text({ content: "Home content here" })),
  files: Box({ padding: 1 }, Text({ content: "File browser here" })),
  settings: Box({ padding: 1 }, Text({ content: "Settings form here" })),
}

// Create the tabbed container
const container = Box({
  width: 60,
  height: 20,
  borderStyle: "rounded",
})

const tabs = TabSelect({
  width: 60,
  tabWidth: 20,
  options: [
    { name: "Home", description: "Dashboard" },
    { name: "Files", description: "Browse files" },
    { name: "Settings", description: "Preferences" },
  ],
})

// Content area
let currentPanel = panels.home
const contentArea = Box({
  flexGrow: 1,
  padding: 1,
})
contentArea.add(currentPanel)

// Handle tab changes
tabs.on("itemSelected", (index, option) => {
  // Remove current panel
  if (currentPanel) {
    contentArea.remove(currentPanel.id)
  }
  // Add new panel based on selection
  switch (option.name) {
    case "Home":
      currentPanel = panels.home
      break
    case "Files":
      currentPanel = panels.files
      break
    case "Settings":
      currentPanel = panels.settings
      break
  }
  contentArea.add(currentPanel)
})

container.add(tabs)
container.add(contentArea)

tabs.focus()
renderer.root.add(container)

Programmatic Control

// Get current tab index
const currentIndex = tabs.getSelectedIndex()

// Set tab programmatically
tabs.setSelectedIndex(1)

// Update tabs dynamically
tabs.setOptions([
  { name: "New Tab 1", description: "Updated" },
  { name: "New Tab 2", description: "Also updated" },
])

Scroll Behavior

When there are more tabs than fit in the width, the component automatically handles horizontal scrolling as you navigate with the keyboard.