Skip to content

Layout Widgets

Layout widgets in @termuijs/widgets handle structural concerns, grouping, scrolling, centering, and status display.

Card

A bordered container with an optional title embedded in the top border:

·CODE
import { Card } from '@termuijs/widgets'
import { Text } from '@termuijs/widgets'

const card = new Card({ flexGrow: 1 }, { title: 'System Status' })
card.addChild(new Text('CPU: 42%', {}))
card.addChild(new Text('MEM: 58%', {}))
OptionTypeDescription
titlestringText shown centered in the top border line
borderColorColorColor of the border and title text

Card always has border: 'single' and padding: 1 by default. Pass overrides in the style argument.

ScrollView

A vertically scrollable container. Content that overflows the height can be scrolled with arrow keys:

·CODE
import { ScrollView } from '@termuijs/widgets'

const scroll = new ScrollView({ height: 20, flexGrow: 1 }, { scrollbar: true })
for (const line of logLines) {
    scroll.addChild(new Text(line, {}))
}
OptionTypeDefaultDescription
scrollbarbooleantrueShow a scrollbar on the right edge

Keyboard: / scroll one line; PageUp/PageDown scroll by half the visible height; Home/End jump to top/bottom.

Center

Centers a single child widget within its available space:

·CODE
import { Center } from '@termuijs/widgets'
import { Text } from '@termuijs/widgets'

const centered = new Center({ flexGrow: 1 }, {})
centered.addChild(new Text('Loading...', { bold: true }))
OptionTypeDefaultDescription
axis`'x' \'y' \'both'`

Columns

Evenly-split column layout from an array of widgets:

·CODE
import { Columns } from '@termuijs/widgets'

const cols = new Columns({ flexGrow: 1 }, { gap: 1 })
cols.addChildren([cpuGauge, memGauge, diskGauge, netGauge])
OptionTypeDefaultDescription
gapnumber0Column gap in characters

Each child gets an equal share of the available width. For unequal columns, use the row intrinsic with explicit flexGrow values.

A navigable sidebar with items, optional badges, and active item highlighting:

·CODE
import { Sidebar } from '@termuijs/widgets'

const sidebar = new Sidebar({ width: 20 }, {
    items: [
        { id: 'dashboard', label: 'Dashboard', badge: '3' },
        { id: 'logs',      label: 'Logs' },
        { id: 'settings',  label: 'Settings' },
    ],
    activeId: 'dashboard',
    onSelect: (id) => navigate(id),
})
OptionTypeDescription
itemsSidebarItem[]List of navigation items
activeIdstringID of the currently active item (highlighted)
onSelect(id: string) => voidCalled when an item is selected with Enter
collapsedbooleanShow only icons/initials (narrow mode)

SidebarItem: { id: string, label: string, badge?: string, icon?: string }

Keyboard: / to navigate, Enter to select.

KeyValue

Aligned key–value pairs, left-padded so all values line up in a column:

·CODE
import { KeyValue } from '@termuijs/widgets'

const info = new KeyValue({ flexGrow: 1 }, {
    data: {
        'Node version': process.version,
        'Platform':     process.platform,
        'Arch':         process.arch,
        'PID':          String(process.pid),
    },
    separator: ' : ',
})
OptionTypeDefaultDescription
dataRecord<string, string>RequiredKey–value pairs to display
separatorstring' : 'String between key and value
keyColorColor-Color for the key column
valueColorColor-Color for the value column

Definition

Term + definition stacked pairs, like a glossary or CLI man-page style reference:

·CODE
import { Definition } from '@termuijs/widgets'

const glossary = new Definition({ flexGrow: 1 }, {
    items: [
        { term: 'TUI', definition: 'Terminal User Interface — an interactive app that runs inside a terminal emulator.' },
        { term: 'Fiber', definition: 'Internal reconciler node tracking component state and hook calls.' },
    ],
})

Each term is rendered bold; the definition follows on the next line, indented.

A full-width alert with a title and optional body text:

·CODE
import { Banner } from '@termuijs/widgets'

const alert = new Banner({ flexGrow: 1 }, {
    title: 'Deployment Failed',
    message: 'Build step exited with code 1. Check the logs for details.',
    variant: 'error',
})
OptionTypeDescription
titlestringBold header line
messagestringBody text (optional)
variant`'info' \'success' \

StatusMessage

Compact single-line status with an icon and a message:

·CODE
import { StatusMessage } from '@termuijs/widgets'

const msg = new StatusMessage({ height: 1 }, {
    message: 'Connected to database',
    variant: 'success',
})

Icons: / [+] for success, / [x] for error, / [!] for warning, / [i] for info. ASCII fallbacks activate when NO_UNICODE=1.

SplitPane

Divides its container into two resizable panes separated by a draggable divider.

PropTypeDescription
direction'horizontal' | 'vertical'Axis of the split
initialRationumberInitial size of the first pane as a fraction of total (0–1)
minSizenumberMinimum size in characters for either pane
·CODE
import { SplitPane } from '@termuijs/widgets'

const pane = new SplitPane({ flexGrow: 1 }, { direction: 'horizontal', initialRatio: 0.3 })
pane.addChild(sidebar)
pane.addChild(mainContent)

Stack

A flex container that lays out children in a single direction with optional gap and alignment.

PropTypeDescription
direction'row' | 'column'Layout axis
gapnumberSpace between children in characters
align'start' | 'center' | 'end'Cross-axis alignment
·CODE
import { Stack } from '@termuijs/widgets'

const stack = new Stack({ flexGrow: 1 }, { direction: 'column', gap: 1 })
stack.addChildren([header, body, footer])

Masonry

Arranges children in a multi-column grid, filling columns from top to bottom.

PropTypeDescription
columnsnumberNumber of columns
gapnumberGap between items in characters
·CODE
import { Masonry } from '@termuijs/widgets'

const grid = new Masonry({ flexGrow: 1 }, { columns: 3, gap: 1 })
cards.forEach(c => grid.addChild(c))

Fill

Fills its container with a repeated character or color, useful as a background layer.

PropTypeDescription
charstringCharacter to fill with (default: space)
colorColorBackground fill color
·CODE
import { Fill } from '@termuijs/widgets'

const bg = new Fill({ flexGrow: 1 }, { char: '·', color: { type: 'named', name: 'brightBlack' } })

AspectRatio

Constrains a child to a fixed aspect ratio, padding the remaining space.

PropTypeDescription
rationumberWidth-to-height ratio, e.g. 2 for 2:1
·CODE
import { AspectRatio } from '@termuijs/widgets'

const frame = new AspectRatio({ flexGrow: 1 }, { ratio: 2 })
frame.addChild(preview)

Dock

Pins child widgets to edges (top, bottom, left, right) while a central content area fills the rest.

PropTypeDescription
topWidgetWidget docked to the top edge
bottomWidgetWidget docked to the bottom edge
leftWidgetWidget docked to the left edge
rightWidgetWidget docked to the right edge
·CODE
import { Dock } from '@termuijs/widgets'

const layout = new Dock({ flexGrow: 1 }, { top: menuBar, bottom: statusBar })
layout.addChild(editorPane)

Accordion

Groups multiple collapsible sections under labeled headers. Only one section is open at a time by default.

PropTypeDescription
sectionsAccordionSection[]Array of { title, content } objects
multiplebooleanAllow multiple sections open simultaneously
·CODE
import { Accordion } from '@termuijs/widgets'

const widget = new Accordion({ flexGrow: 1 }, {
    sections: [
        { title: 'General', content: generalWidget },
        { title: 'Advanced', content: advancedWidget },
    ],
})

Collapsible

A single collapsible section with a toggle header. Press Enter or Space to expand or collapse.

PropTypeDescription
titlestringHeader text
openbooleanInitial open state
onToggle(open: boolean) => voidCalled when the open state changes
·CODE
import { Collapsible } from '@termuijs/widgets'

const widget = new Collapsible({ flexGrow: 1 }, { title: 'Details', open: false })
widget.addChild(detailsWidget)

Displays one child at a time and lets the user cycle through them with arrow keys.

PropTypeDescription
loopbooleanWrap around from last to first slide
showIndicatorbooleanShow dot indicator below slides
·CODE
import { Carousel } from '@termuijs/widgets'

const slides = new Carousel({ flexGrow: 1 }, { loop: true, showIndicator: true })
slides.addChildren([slide1, slide2, slide3])

See also