Skip to content

TabSelect

TabSelect displays a row of tabs. It supports auto-width or fixed-width tabs, an active underline, scroll arrows when tabs overflow, and optional per-tab descriptions.

import {
TabSelect,
TabSelectEvents,
type TabOption,
createCliRenderer,
} from '@bettertui/core';
const renderer = await createCliRenderer({ exitOnCtrlC: true });
const tabs: TabOption[] = [
{ name: 'Overview', description: 'Summary view', value: 'overview' },
{ name: 'Files', description: 'File browser', value: 'files' },
{ name: 'Settings', description: 'App configuration', value: 'settings' },
];
const tabBar = new TabSelect(renderer, {
options: tabs,
width: '100%',
height: 3,
showUnderline: true,
showDescription: true,
activeUnderlineColor: '#7aa2f7',
selectedTextColor: '#7aa2f7',
textColor: '#565f89',
});
tabBar.on(TabSelectEvents.ITEM_SELECTED, (_index, option) => {
console.log('Tab selected:', option.value);
});
renderer.root.add(tabBar);
tabBar.focus();
renderer.start();
new TabSelect(renderer: CliRenderer, options?: TabSelectOptions)

TabSelectOptions extends BoxOptions with:

Prop Type Default Description
options TabOption[] [] Tab definitions
selectedIndex number 0 Initially selected tab
tabWidth number 0 Fixed tab width (0 = auto)
minTabWidth number 8 Minimum width in auto mode
tabPadding number 2 Padding on each side of label
tabGap number 1 Gap between tabs
showDescription boolean true Show description below tab bar
showUnderline boolean true Show active tab underline
showScrollArrows boolean true Show ◄ ► when tabs overflow
scrollArrowLeft string '◄' Left scroll arrow glyph
scrollArrowRight string '►' Right scroll arrow glyph
wrapSelection boolean false Wrap around at edges
textColor string Inactive tab text color
selectedTextColor string Active tab text color
selectedBackgroundColor string Active tab background color
activeUnderlineColor string Underline color for active tab
inactiveUnderlineColor string Underline color for inactive tabs
descriptionColor string Description text color
interface TabOption {
name: string; // Tab label
description?: string; // Description shown below the bar
value?: unknown; // Arbitrary payload
}
tabBar.focus(): void
tabBar.blur(): void
tabBar.getSelectedIndex(): number
tabBar.getSelectedOption(): TabOption | null
Event Payload When
TabSelectEvents.SELECTION_CHANGED (index, option) Highlighted tab changes
TabSelectEvents.ITEM_SELECTED (index, option) User confirms with Enter
RenderableEvents.FOCUSED TabSelect gains focus
RenderableEvents.BLURRED TabSelect loses focus
Key Action
/ [ Previous tab
/ ] Next tab
Enter Confirm selection
const tabs = new TabSelect(renderer, {
options: [
{ name: 'Files', value: 'files' },
{ name: 'Preview', value: 'preview' },
{ name: 'Output', value: 'output' },
],
width: '100%',
showDescription: false,
activeUnderlineColor: '#9ece6a',
selectedTextColor: '#9ece6a',
});
renderer.root.add(tabs);
tabs.focus();
const layout = new Box(renderer, { flexDirection: 'column', width: '100%', height: '100%' });
const tabBar = new TabSelect(renderer, {
options: [
{ name: 'Tab 1', value: 0 },
{ name: 'Tab 2', value: 1 },
{ name: 'Tab 3', value: 2 },
],
width: '100%',
height: 3,
});
const content = new Text(renderer, { content: 'Tab 1 content', flexGrow: 1 });
tabBar.on(TabSelectEvents.SELECTION_CHANGED, (_i, opt) => {
content.content = `Tab ${(opt.value as number) + 1} content`;
});
layout.add(tabBar);
layout.add(content);
renderer.root.add(layout);
tabBar.focus();