docs/components/tab-select.mdx
docs/components/tab-select.mdxBrowse 89 files
7,102 bytes
Token encoding: o200k_base
Snapshot ac753b4
title: TabSelect description: Choose one option from a horizontal tab list
TabSelect
TabSelect shows peer choices in a horizontal tab strip and scrolls the strip as the selection moves. Use Select for a vertical option list.
Focus the component to receive keyboard input.
Availability
| Field | Availability |
|---|---|
| Package | @opentui/core |
| Core renderable | TabSelectRenderable |
| React | <tab-select> (automatic) |
| Solid | <tab_select> (automatic) |
| Status | Built in |
Basic usage
Renderable API
import { TabSelectRenderable, TabSelectRenderableEvents, createCliRenderer } from "@opentui/core"
const renderer = await createCliRenderer()
const tabs = new TabSelectRenderable(renderer, {
id: "tabs",
width: 36,
options: [
{ name: "Home", description: "View project overview" },
{ name: "Files", description: "Browse project files" },
{ name: "Settings", description: "Configure the project" },
],
tabWidth: 12,
})
tabs.on(TabSelectRenderableEvents.ITEM_SELECTED, (index, option) => {
console.log("Tab selected:", option.name)
})
tabs.focus()
renderer.root.add(tabs)
After pressing Right, Files is selected:
Home Files Settings
▬▬▬▬▬▬▬▬▬▬▬▬
Browse project files
Keyboard navigation
When focused, the tab select responds to these keys:
| Key | Action |
|---|---|
Left / [ | Move to previous tab |
Right / ] | Move to next tab |
Enter | Select 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 update
Emitted after successful movement or a valid setSelectedIndex() call:
import { TabSelectRenderableEvents, type TabSelectOption } from "@opentui/core"
tabs.on(TabSelectRenderableEvents.SELECTION_CHANGED, (index: number, option: TabSelectOption) => {
console.log(`Hovering: ${option.name}`)
})
Every valid setSelectedIndex() call emits the event, even when it assigns the current index. A blocked directional
movement does not emit it.
Properties
| Property | Type | Default | Description |
|---|---|---|---|
width | number | - | Total component width |
options | TabSelectOption[] | [] | Available tabs |
tabWidth | number | 20 | Width of each tab |
backgroundColor | string | RGBA | transparent | Background color |
textColor | string | RGBA | #FFFFFF | Normal tab text |
focusedBackgroundColor | string | RGBA | initial base color | Background color when focused |
focusedTextColor | string | RGBA | initial base color | Text color when focused |
selectedBackgroundColor | string | RGBA | #334455 | Selected tab background |
selectedTextColor | string | RGBA | #FFFF00 | Selected tab text |
selectedDescriptionColor | string | RGBA | #CCCCCC | Description text color |
showScrollArrows | boolean | true | Show scroll indicators |
showDescription | boolean | true | Show tab descriptions |
showUnderline | boolean | true | Show underline on selected tab |
wrapSelection | boolean | false | Wrap around when navigating |
keyBindings | TabSelectKeyBinding[] | - | Custom key bindings |
keyAliasMap | Record<string, string> | - | Key alias mappings |
If you omit a focused color, the constructor copies the corresponding base color. If you omit both values, the focused
background uses #1a1a1a, and the focused text uses #FFFFFF.
Example: tabbed interface
import {
BoxRenderable,
TabSelectRenderable,
TabSelectRenderableEvents,
TextRenderable,
createCliRenderer,
} from "@opentui/core"
const renderer = await createCliRenderer()
function createPanel(content: string) {
const panel = new BoxRenderable(renderer, { padding: 1 })
panel.add(new TextRenderable(renderer, { content }))
return panel
}
const panels = {
home: createPanel("Home content here"),
files: createPanel("File browser here"),
settings: createPanel("Settings form here"),
}
const container = new BoxRenderable(renderer, {
width: 60,
height: 20,
borderStyle: "rounded",
})
const tabs = new TabSelectRenderable(renderer, {
width: 60,
tabWidth: 20,
options: [
{ name: "Home", description: "Dashboard" },
{ name: "Files", description: "Browse files" },
{ name: "Settings", description: "Preferences" },
],
})
let currentPanel = panels.home
const contentArea = new BoxRenderable(renderer, {
flexGrow: 1,
padding: 1,
})
contentArea.add(currentPanel)
tabs.on(TabSelectRenderableEvents.ITEM_SELECTED, (_index, option) => {
contentArea.remove(currentPanel)
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)
renderer.root.add(container)
tabs.focus()
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.
Related concepts
Read Interaction, focus, and selection for focus and event behavior. Use ScrollBox for content scrolling that is independent of the tab strip.