Layout & Styling
The terminal renderer walks your component tree into an array of ANSI-styled lines and paints them every frame. This guide covers the three intrinsic elements, the line layout model, and how colors and borders work.
The intrinsic elements
@sigx/terminal provides three host elements you can use in TSX:
box— a block container that can draw a border, a centered label, a background and a drop shadow.text— an inline run of text, optionally colored.br— a hard line break that starts a new line.
/** @jsxImportSource @sigx/terminal */
import { component, defineApp } from '@sigx/terminal';
const App = component(() => {
return () => (
<box border="single" label="Demo">
<text>First line of </text>
<text color="cyan">inline text.</text>
<br />
<text>Second line after a break.</text>
</box>
);
});
defineApp(<App />).mount({ clearConsole: true });
How layout works
The layout is a simple inline/block line flow — not a full flexbox engine. There are no row/column, justify or align props. The rules are:
- A
box(and any element whose immediate child is abox) is treated as a block — it gets its own lines. textand other single-line children are appended inline to the current line.- A
brforces a new line. - Multi-line non-box children are promoted to block so they don't break a surrounding border.
So to stack content vertically, wrap each row in its own box, or separate runs with br:
<box border="rounded" label="Stacked">
<box><text>Row one</text></box>
<box><text>Row two</text></box>
<box><text>Row three</text></box>
</box>
Layout primitives
For real horizontal and vertical layout, the foundation ships components that compose box for you:
Box— the themed container:border(single/double/rounded/thick/none),borderColor,backgroundColor,label,labelColor,padX,dropShadow.Row— lays children out horizontally with agapandalign(start/center/end, plustop/bottom).Col— stacks children vertically with agap.Spacer— inserts blanksizelines (vertical spacing).Divider— a horizontal rule with an optional centeredlabelandcolor.
/** @jsxImportSource @sigx/terminal */
import { component, defineApp, Box, Row, Col, Divider } from '@sigx/terminal';
const App = component(() => {
return () => (
<Box border="rounded" label="Dashboard">
<Row gap={2} align="center">
<Box border="single" label="Left"><text>A</text></Box>
<Box border="single" label="Right"><text>B</text></Box>
</Row>
<Divider label="logs" />
<Col gap={1}>
<text>line one</text>
<text>line two</text>
</Col>
</Box>
);
});
defineApp(<App />).mount({ clearConsole: true });
The box/text/br intrinsics below are the lower-level host elements these primitives render to. Use the intrinsics for fine control or the primitives for ordinary layout.
Borders
The border prop accepts single, double, rounded or thick. To draw no border, use none (the Box component) or omit the prop entirely (the box intrinsic):
<box border="single">...</box> {/* ┌─┐ │ └─┘ */}
<box border="double">...</box> {/* ╔═╗ ║ ╚═╝ */}
<box border="rounded">...</box> {/* ╭─╮ │ ╰─╯ */}
<box border="thick">...</box> {/* ┏━┓ ┃ ┗━┛ */}
<box>...</box> {/* no border */}
The renderer only draws a border when the
borderprop is truthy, and any unrecognized value falls back to the single-line style. Soborder="none"currently still renders a single border — leave the prop off to get no border at all.
Set borderColor to color the border with a named color, and label to render a centered caption in the top border, like a fieldset legend:
<box border="rounded" borderColor="cyan" label="Settings">
<text>Configuration goes here.</text>
</box>
Colors
Colors use a fixed named palette mapped to ANSI codes:
red, green, blue, yellow, cyan, white, black.
<box backgroundColor="blue" borderColor="white">
<text color="yellow">Warning</text>
<br />
<text color="green">OK</text>
</box>
colorstyles text foreground.backgroundColorfills the box padding and border area.borderColorcolors the border characters.
Only the named palette resolves to an ANSI code. Arbitrary strings or hex values such as
#666666produce no color, so stick to the named set.
Drop shadow
dropShadow adds a gray shadow on the right and bottom edges of a box:
<box border="single" label="Card" dropShadow={true}>
<text>This box casts a shadow.</text>
</box>
Putting it together
/** @jsxImportSource @sigx/terminal */
import { component, defineApp, signal } from '@sigx/terminal';
const App = component(() => {
const status = signal<'ok' | 'warn'>('ok');
return () => (
<box border="rounded" label="Dashboard" borderColor="cyan" dropShadow={true}>
<box>
<text>Status: </text>
<text color={status.value === 'ok' ? 'green' : 'yellow'}>
{status.value === 'ok' ? 'Healthy' : 'Degraded'}
</text>
</box>
<box backgroundColor="blue">
<text color="white">Background-filled row</text>
</box>
</box>
);
});
defineApp(<App />).mount({ clearConsole: true });
Tokens vs named colors
The named palette above maps to fixed ANSI codes. The themed components and the Box/Text primitives instead accept theme tokens (accent, fg, line, …) that resolve against the active theme and adapt to the terminal's color depth — see Theming. Use named colors for quick scripts; use tokens for themed apps.
Next steps
- Typography —
TextandHeadingfor styled, token-aware text. - Theming — semantic tokens and the built-in themes.
- Input & Interactive Components — focus and the built-in widgets.
- Components — the full component library.
- API Reference — the full export list.
