Text & Styling

Colors, attributes and theme tokens for a deployment card with live status.

This chapter's app is running in your console. Open it with ⌘⌥JCtrl+Shift+J, then try it.
Watch the chapter3:26 · narrated · captions

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:

app/status.tsx+15tsx
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.

app/page.tsx+23-1tsx
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.

▼ 03 · Text & Styling

Open the console

⌘⌥J
CtrlShiftJ

The app renders in DevTools. Then click here and press t.

TthemeSstatus

Open on a desktop

This demo renders in the Chrome DevTools console, which needs a desktop browser.

Quiz

2 questions

Answer every question to complete the chapter.

Why use color="success" instead of a hex value?

 

What does wrap="truncate-end" do?