Text & Styling
Colors, attributes and theme tokens for a deployment card with live status.
In this chapter
- Text attributes
- Theme tokens
- A deployment card
- Themes
Every cell has a character, a foreground, a background and a set of attributes. Text.js compiles them into %c CSS spans, so the console shows real colors, bold and italics.
Text attributes
<Text> takes bold, dim, italic, underline and strikethrough. Nested <Text> elements become styled spans inside one line.
<Text> Deployed <Text bold>acme-web</Text> to <Text color="accent">iad1</Text></Text>Theme tokens
The color prop accepts hex values, plain color names (emerald) and theme tokens; Tailwind palette shades go through classes (text-emerald-400). Tokens follow the active theme, so prefer them for anything semantic. Add a status component:
Added: import { Text } from "@textjs/next";Added: Added: export type DeployStatus = "ready" | "building" | "error" | "queued";Added: Added: export const STATUS = {Added: ready: { label: "Ready", color: "success" },Added: building: { label: "Building", color: "warning" },Added: error: { label: "Error", color: "danger" },Added: queued: { label: "Queued", color: "subtle" },Added: } as const;Added: Added: export function Status({ status }: { status: DeployStatus }) {Added: const s = STATUS[status];Added: return <Text color={s.color} wrap="nowrap">{`● ${s.label}`}</Text>;Added: }A deployment card
bg-surface raises the card off the background. The deployment id picks up the status color, goes italic while building and is struck through on error.
Removed: import { Box, Spacer, Text, useInput } from "@textjs/next";Added: import { Box, Spacer, Text, useAppTheme, useInput } from "@textjs/next";Added: import { Status, STATUS, type DeployStatus } from "./status";Added: Added: const ORDER: DeployStatus[] = ["ready", "building", "error", "queued"];Added: export default function Page() {Added: const { theme, cycleTheme } = useAppTheme();Added: const [status, setStatus] = useState<DeployStatus>("ready");Added: Added: useInput((e) => {Added: if (e.input === "t") cycleTheme();Added: if (e.input === "s") setStatus((s) => ORDER[(ORDER.indexOf(s) + 1) % ORDER.length]);Added: });Added: return ( <Box className="flex-col grow"> {/* top bar, now with the theme name on the right */}Added: <Box className="flex-col border rounded px-2 py-1 bg-surface">Added: <Box className="flex-row gap-2 h-1">Added: <Text bold>acme-web</Text>Added: <Status status={status} />Added: </Box>Added: <Text color="muted" wrap="truncate-end">feat: stream cells downward</Text>Added: <Text color={STATUS[status].color} italic={status === "building"} strikethrough={status === "error"}>Added: dpl_8fK2Added: </Text>Added: </Box> </Box> );}wrap="truncate-end" ends long commit messages with … instead of wrapping onto a second row.
Themes
Five themes ship with Text.js: Geist Dark, OpenCode Dark, Tokyo Night, Amber CRT and Geist Light. Press t in the console to cycle them. The whole frame repaints in the new palette, because every color above is a token.
Try it
This is Acme Deploys at the end of the chapter, running in DevTools. Click the pad, then use the keys below.
Open the console
The app renders in DevTools. Then click here and press t.
Open on a desktop
This demo renders in the Chrome DevTools console, which needs a desktop browser.
Quiz
2 questionsAnswer every question to complete the chapter.