Widgets
Every widget HQTUI draws, what it actually looks like, and the code that drew it. The pictures are not screenshots: each one is rendered headlessly at build time by the library itself, and each snippet is a region of a program that compiles and runs. If a widget stopped drawing, this page would go blank rather than lie.
| Language | Widgets | Gallery |
|---|---|---|
| TypeScript | 28 / 28 | examples/widgets/gallery.ts |
| JavaScript | 28 / 28 | examples/widgets/gallery.js |
| Rust | 28 / 28 | ports/rust/examples/widgets.rs |
| Go | 28 / 28 | ports/go/examples/widgets/main.go |
| Python | 28 / 28 | ports/python/examples/widgets.py |
| Zig | 28 / 28 | ports/zig/examples/widgets.zig |
| C++ | 7 / 28 | ports/cpp/examples/widgets.cpp |
| Ruby | 8 / 28 | ports/ruby/examples/widgets.rb |
| PHP | 8 / 28 | ports/php/examples/widgets.php |
| Perl | 8 / 28 | ports/perl/examples/widgets.pl |
| COBOL | 8 / 28 | ports/cobol/examples/widgets.cbl |
Text
Text
textTextAligned, styled, optionally wrapped copy. Every other widget is built on it.
Plain text. It fills the width it is given. Bold, in the theme's primary color. Right aligned. Long copy wraps when you ask it to, instead of being cut at the edge.
export function text(ui: Container, theme: Theme): void {
ui.text("Plain text. It fills the width it is given.");
ui.text("Bold, in the theme's primary color.", { bold: true, fg: theme.primary });
ui.text("Right aligned.", { align: "right" });
ui.text("Long copy wraps when you ask it to, instead of being cut at the edge.", { wrap: true });
}Label
labelTextText in the theme's muted color: captions and the line under a number.
cpu · 8 cores · 3.4 GHz 42.1% 15 minute average
export function label(ui: Container, theme: Theme): void {
// `label` is `text` in the theme's muted color: secondary copy, captions,
// the line under a number that says what the number is.
ui.label("cpu · 8 cores · 3.4 GHz");
ui.text("42.1%", { bold: true, fg: theme.success });
ui.label("15 minute average");
}Not in 5 of the 11 ports yet. C++, Ruby, PHP and Perl reach the library through a narrower native core.
Heading
headingTextBold text in the theme's title color, for sectioning without a panel.
Storage Four volumes, one degraded Network
export function heading(ui: Container, theme: Theme): void {
// `heading` is `text` in the theme's title color, bold.
ui.heading("Storage");
ui.label("Four volumes, one degraded");
ui.spacer(1);
ui.heading("Network", { fg: theme.accent });
}Not in 5 of the 11 ports yet. C++, Ruby, PHP and Perl reach the library through a narrower native core.
Badge
badgeTextA status chip. Filled, subtle or outline.
active idle failed
export function badge(ui: Container, theme: Theme): void {
ui.row({ size: 1, gap: 1 }, (r) => {
r.badge({ text: "active", color: theme.success, size: 10 });
r.badge({ text: "idle", color: theme.warning, variant: "subtle", size: 8 });
r.badge({ text: "failed", color: theme.danger, variant: "outline", size: 10 });
r.spacer("fill");
});
}Not in 5 of the 11 ports yet. C++, Ruby, PHP and Perl reach the library through a narrower native core.
Divider
dividerTextA rule, optionally labelled, that titles a section cheaply.
Above the line ────────────────────────────────────────────────────────── Below it ───────────────────────── status ───────────────────────── A labelled divider titles a section without spending a pa…
export function divider(ui: Container, theme: Theme): void {
ui.text("Above the line");
ui.divider();
ui.text("Below it");
ui.divider({ label: "status", align: "center", color: theme.accent });
ui.text("A labelled divider titles a section without spending a panel on it");
}Not in 1 of the 11 ports yet. C++, Ruby, PHP and Perl reach the library through a narrower native core.
Key/values
keyValuesTextAligned label and value pairs. The backbone of every system panel.
Host web-01.iad Uptime 18d 04:12 Load 0.42 0.51 0.60 Established 1,284
export function keyValues(ui: Container, theme: Theme): void {
// The backbone of every "System" panel: labels left, values right.
ui.keyValues([
{ label: "Host", value: "web-01.iad" },
{ label: "Uptime", value: "18d 04:12" },
{ label: "Load", value: "0.42 0.51 0.60", color: theme.warning },
{ label: "Established", value: "1,284", color: theme.success },
]);
}Status bar
statusBarTextThe keybinding strip along the bottom, with a right-hand slot.
F1 Help F2 Theme F3 Filter ^K Palette q Quit 0.41ms 18…
export function statusBar(ui: Container, _theme: Theme): void {
// Usually the last thing drawn, pinned to the bottom row.
ui.statusBar({
items: [
{ key: "F1", label: "Help" },
{ key: "F2", label: "Theme" },
{ key: "F3", label: "Filter", active: true },
{ key: "^K", label: "Palette" },
{ key: "q", label: "Quit" },
],
right: [{ label: "0.41ms 184 cells" }],
});
}Not in 5 of the 11 ports yet. C++, Ruby, PHP and Perl reach the library through a narrower native core.
Data
Table
tableDataColumns with alignment, widths, zebra striping, selection and scroll.
Name Size Type Modified src 4.2 KB dir 2m ago test 1.1 KB dir 5m ago package.json 1.2 KB file 10m ago README.md 3.4 KB file 1h ago
export function table(ui: Container, theme: Theme): void {
ui.table({
rows: [
{ name: "src", size: "4.2 KB", type: "dir", modified: "2m ago" },
{ name: "test", size: "1.1 KB", type: "dir", modified: "5m ago" },
{ name: "package.json", size: "1.2 KB", type: "file", modified: "10m ago" },
{ name: "README.md", size: "3.4 KB", type: "file", modified: "1h ago" },
],
selected: 1,
zebra: true,
columns: [
{ key: "name", title: "Name", min: 12, color: theme.primary },
{ key: "size", title: "Size", width: 9, align: "right" },
{ key: "type", title: "Type", width: 6 },
{ key: "modified", title: "Modified", width: 10, align: "right", color: theme.muted },
],
});
}List
listDataA selectable list with bullets and its own scrollbar.
▸ apps/demo ▸ packages/hqtui ▸ apps/web ▸ docs
export function list(ui: Container, theme: Theme): void {
ui.list({
items: [
{ label: "apps/demo", color: theme.primary },
{ label: "packages/hqtui" },
{ label: "apps/web" },
{ label: "docs" },
],
selected: 0,
bullet: "▸",
scrollbar: true,
});
}Not in 5 of the 11 ports yet. C++, Ruby, PHP and Perl reach the library through a narrower native core.
Tree
treeDataNested rows with expand state and per-node value columns.
└─ systemd 1.3 ├─ bash 0.1 ├─ bun 32.8 │ └─ bun:worker 12.4 └─ postgres 6.7
export function tree(ui: Container, _theme: Theme): void {
ui.tree({
nodes: [
{
label: "systemd",
expanded: true,
values: [{ text: "1.3", width: 6 }],
children: [
{ label: "bash", values: [{ text: "0.1", width: 6 }] },
{
label: "bun",
expanded: true,
values: [{ text: "32.8", width: 6 }],
children: [{ label: "bun:worker", values: [{ text: "12.4", width: 6 }] }],
},
{ label: "postgres", values: [{ text: "6.7", width: 6 }] },
],
},
],
selected: 2,
});
}Not in 5 of the 11 ports yet. C++, Ruby, PHP and Perl reach the library through a narrower native core.
Log
logDataLevelled log lines that tail by default and scroll back from the end.
12:45:02 INFO listening on :8080 12:45:09 WARN slow query 412ms {table=users} 12:45:11 ERROR upstream timeout 12:45:14 INFO retry succeeded
export function log(ui: Container, _theme: Theme): void {
ui.log({
entries: [
{ time: "12:45:02", level: "info", message: "listening on :8080" },
{ time: "12:45:09", level: "warn", message: "slow query 412ms", meta: "{table=users}" },
{ time: "12:45:11", level: "error", message: "upstream timeout" },
{ time: "12:45:14", level: "info", message: "retry succeeded" },
],
// Lines scrolled back from the newest. 0 keeps it tailing.
fromEnd: 0,
scrollbar: true,
});
}Meters
Meter
meterMetersA labelled bar. Smooth or segmented, heat-colored by default.
CPU ████████████████████████▊─────────────── 62% MEM ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮ 31% SWP ██████████████████████████████████▊───── 87%
export function meter(ui: Container, theme: Theme): void {
ui.meter({ label: "CPU", value: 0.62, style: "smooth", color: theme.primary });
ui.meter({ label: "MEM", value: 0.31, style: "segmented" });
ui.meter({ label: "SWP", value: 0.87, style: "smooth" });
}Meters
metersMetersA whole bank of meters in one call, laid out in columns.
P0 ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮ 12% P4 ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮ 38% P1 ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮ 44% P5 ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮ 55% P2 ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮ 71% P6 ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮ 22% P3 ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮ 9% P7 ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮ 66%
export function meters(ui: Container, _theme: Theme): void {
// One call for a whole bank. `columns` lays them out side by side.
ui.meters(
[0.12, 0.44, 0.71, 0.09, 0.38, 0.55, 0.22, 0.66].map((value, i) => ({ label: `P${i}`, value })),
{ columns: 2, labelWidth: 4, valueWidth: 5, style: "segmented" },
);
}Not in 5 of the 11 ports yet. C++, Ruby, PHP and Perl reach the library through a narrower native core.
Progress
progressMetersA determinate bar that can show a count as well as a ratio.
Indexing █████████▉────────────────────── 37/120 Upload ██████████████████████████████▍────── 82%
export function progress(ui: Container, _theme: Theme): void {
ui.progress({ label: "Indexing", value: 37, max: 120, showCount: true });
ui.progress({ label: "Upload", value: 0.82 });
}Not in 5 of the 11 ports yet. C++, Ruby, PHP and Perl reach the library through a narrower native core.
Graph
graphMetersA Braille line chart, optionally filled under the curve.
⢀⣀⠤⣀ ⢀⡠⢄⡀▄ ▁⢀⠤⠒⠉⠁███⠉⠒⠤⡀ ⢀⡠⠊⠁▅█⠈⠒⠤⣀ ⡠⠒⠁██████████⠈⠑⠤⣀ ⢀⡠⠒⠉⠒⠢⠔⠁▃████████⠉⠒⠒⠉⠉████████████████▇⠉⠑⠒⠤⠤⠒⠒ ⢀⡠⠤⢄⣀⡠⠔⠊⠁▆▆███████████████████████████████████████████ ⣀⠤⠔⠊⠁▅████████████████████████████████████████████████████ ██████████████████████████████████████████████████████████
export function graph(ui: Container, theme: Theme): void {
// Braille line chart. `fill` shades the area under the curve.
ui.graph({ values: CPU_HISTORY, min: 0, max: 100, fill: true, color: theme.success, size: "1fr" });
}Sparkline
sparklineMetersOne row: label, inline chart and a value.
CPU ▁▂▃▂▃▅▄▆▇▅▄▅▆▇█▇▆▅▄▅ 44% Mem ▁▂▁▃▅▄█▇▅▃▂▄▆█▇▅ 31% Net ▁▂▃▂▃▅▄▆▇▅▄▅▆▇█▇▆▅▄▅ 2.4 MB/s
export function sparkline(ui: Container, theme: Theme): void {
ui.sparkline({ label: "CPU ", values: CPU_HISTORY, text: "44%", color: theme.success });
ui.sparkline({ label: "Mem ", values: NET_HISTORY, text: "31%", color: theme.warning });
ui.sparkline({ label: "Net ", values: CPU_HISTORY, text: "2.4 MB/s", color: theme.primary });
}Not in 5 of the 11 ports yet. C++, Ruby, PHP and Perl reach the library through a narrower native core.
Histogram
histogramMetersBlock columns. Cheaper than Braille and easier to read when short.
▃█▁ ▆ ▃███ ▆█▃ ████▅ ▇▂███▃▇█████▆▁▄ ▄███████████████ ▇▄████████████████ ▃███████████████████ ████████████████████
export function histogram(ui: Container, theme: Theme): void {
// Block columns. Cheaper than Braille and easier to read when short.
ui.histogram({ values: CPU_HISTORY, color: theme.accent, size: "1fr" });
}Not in 5 of the 11 ports yet. C++, Ruby, PHP and Perl reach the library through a narrower native core.
Heat bar
heatBarMetersA segmented bar colored along the theme's heat ramp.
▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮ ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮ ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮
export function heatBar(ui: Container, _theme: Theme): void {
// Segmented bar colored along the theme's heat ramp, like btop's temperatures.
ui.heatBar({ value: 0.28 });
ui.heatBar({ value: 0.64 });
ui.heatBar({ value: 0.91 });
}Not in 5 of the 11 ports yet. C++, Ruby, PHP and Perl reach the library through a narrower native core.
Gauge
gaugeMetersA semicircular dial. Wants at least nine columns by five rows.
⢀⣠⣤⡶⠶⠞⠛⠛⠛⠛⠛⠛⠛⠶⠶⣦⣤⣀ ⢀⣠⡶⠟⠋⠉ ⠈⠉⠛⠷⣦⣀ ⢀⡴⠟⠁ ⠙⠷⣄ ⢀⡴⠋ ⠈⠳⣄ ⣠⠟ ⠘⢧⡀ ⢠⠏ ⠈⢧ ⡟ ⠘⡇ ⢸⠃ ⢻ 62%
export function gauge(ui: Container, _theme: Theme): void {
// A semicircular dial. Wants at least 9x5.
ui.gauge({ value: 62, label: "62%" });
}Donut
donutMetersA ring split into labelled, colored segments.
⢀⣤⣴⣶⣿⣿⣿⣿⣿⣿⣷⣶⣤⣄ ⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⡀ ⢀⣼⣿⣿⣿⣿⣿⣿⠿⠛⠛⠛⠛⠻⢿⣿⣿⣿⣿⣿⣿⣄ ⣼⣿⣿⣿⣿⣿⠏ ⠈⢿⣿⣿⣿⣿⣿⡄ ⢠⣿⣿⣿⣿⣿⠇ ⢿⣿⣿⣿⣿⣧ ⠸⣿⣿⣿⣿⣿⡄ ⣼⣿⣿⣿⣿⡿ ⢿⣿⣿⣿⣿⣷⡄ ⣴⣿⣿⣿⣿⣿⠇ ⠘⢿⣿⣿⣿⣿⣿⣷⣤⣀⣀⣀⣀⣠⣴⣿⣿⣿⣿⣿⣿⠟ ⠈⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋ ⠈⠙⠻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠛⠉ ⠉⠉⠉⠉⠉⠉⠁
export function donut(ui: Container, theme: Theme): void {
ui.donut({
segments: [
{ value: 4.65, color: theme.primary, label: "Used" },
{ value: 10.96, color: theme.warning, label: "Free" },
],
});
}Not in 5 of the 11 ports yet. C++, Ruby, PHP and Perl reach the library through a narrower native core.
Inputs
Checkbox
checkboxInputsA checkbox or a toggle, depending on the variant.
[▮ ] Toggle [ ] Checkbox
export function checkbox(ui: Container, _theme: Theme): void {
ui.row({ size: 1, gap: 2 }, (r) => {
r.checkbox({ label: "Toggle", checked: true, variant: "toggle", size: 12 });
r.checkbox({ label: "Checkbox", checked: false, size: 14 });
r.spacer("fill");
});
}Not in 5 of the 11 ports yet. C++, Ruby, PHP and Perl reach the library through a narrower native core.
Select
selectInputsA closed value, or an open dropdown with the current option marked.
Dracula ▴ Dark Dracula Nord Tokyo Night
export function select(ui: Container, _theme: Theme): void {
ui.select({
value: "Dracula",
width: 20,
size: 20,
open: true,
options: ["Dark", "Dracula", "Nord", "Tokyo Night"],
selectedIndex: 1,
});
}Not in 5 of the 11 ports yet. C++, Ruby, PHP and Perl reach the library through a narrower native core.
Text input
textInputInputsA labelled field with a placeholder and a cursor.
Search postgres Filter type to filter…
export function textInput(ui: Container, _theme: Theme): void {
ui.textInput({ label: "Search", value: "postgres", size: 1 });
ui.spacer(1);
ui.textInput({ label: "Filter", value: "", placeholder: "type to filter…", size: 1 });
}Not in 5 of the 11 ports yet. C++, Ruby, PHP and Perl reach the library through a narrower native core.
Tabs
tabsInputsA single row of tabs with one active. Clickable.
1 dashboard 2 traffic 3 sessions 4 network
export function tabs(ui: Container, _theme: Theme): void {
ui.tabs({
tabs: ["1 dashboard", "2 traffic", "3 sessions", "4 network"],
active: 1,
});
}Not in 5 of the 11 ports yet. C++, Ruby, PHP and Perl reach the library through a narrower native core.
Overlays
Modal
modalOverlaysA centered dialog drawn over everything, with buttons.
╭────────────── Confirm Action ──────────────╮ │ │ │ Terminate process 4821 (postgres)? │ │ │ │ This cannot be undone. │ │ │ │ Yes No │ │ │ ╰────────────────────────────────────────────╯
export function modal(ui: Container, _theme: Theme): void {
// Overlays draw over everything already on the screen, centered.
ui.modal({
title: "Confirm Action",
width: 46,
height: 9,
message: "Terminate process 4821 (postgres)?\n\nThis cannot be undone.",
buttons: [
{ label: "Yes", variant: "success", focused: true },
{ label: "No", variant: "ghost" },
],
});
}Not in 5 of the 11 ports yet. C++, Ruby, PHP and Perl reach the library through a narrower native core.
Command palette
commandPaletteOverlaysA query line and filtered results, over the current screen.
╭─ Command Palette ────────────────────────────────────────╮ │› the │ │──────────────────────────────────────────────────────────│ │ Toggle theme F2 │ │ Filter processes F3 │ │ Sort by memory F6 │ ╰──────────────────────────────────────────────────────────╯
export function commandPalette(ui: Container, _theme: Theme): void {
ui.commandPalette({
query: "the",
items: [
{ label: "Toggle theme", hint: "F2" },
{ label: "Filter processes", hint: "F3" },
{ label: "Sort by memory", hint: "F6" },
],
selected: 0,
});
}Not in 5 of the 11 ports yet. C++, Ruby, PHP and Perl reach the library through a narrower native core.
Tooltip
tooltipOverlaysA small floating box anchored at a cell.
Tooltips are overlays positioned at a cell, for hover and hin… ╭──────────────────╮ │swap is 87% full │ ╰──────────────────╯
export function tooltip(ui: Container, _theme: Theme): void {
ui.text("Tooltips are overlays positioned at a cell, for hover and hints.");
ui.tooltip({ text: "swap is 87% full", x: 6, y: 3 });
}Not in 5 of the 11 ports yet. C++, Ruby, PHP and Perl reach the library through a narrower native core.
Want the longer version? The High Quality Terminal UI Cookbook walks through building a real dashboard with these.