Components / Code block

Code block

Showing a copyable snippet — install steps, API examples, generated prompts. One block, one snippet.

import { CodeBlock } from '@layers/ui/code-block'

Rendered stock

House rules

  • maxHeight caps the snippet and scrolls it inside itself. Reach for it when the snippet is something the reader COPIES rather than reads — a generated agent prompt, a long config dump — and its length would otherwise push the action that acts on it off the surface. Leave it off in docs and anywhere the code is the thing being read: a nested scroller nobody asked for is worse than a tall block.
  • copyOnClick makes the whole snippet the copy target: a click anywhere in it copies all of it, and "Copied" shows beside the corner button for two seconds. Use it for text the reader pastes somewhere else (an agent prompt, a terminal command, an ID, a secret), shown open by default. Never hide that text behind a show/hide toggle or put a large primary copy button beside it: people trust what they can read before they paste it. A click that ends a text selection keeps the selection, so part of it can still be copied.
  • wrap breaks long lines inside the block, and a long URL breaks anywhere, so prose never scrolls sideways. Use it for prose in a monospace block (a generated agent prompt, a fix prompt). Code keeps the default: a wrapped line of code reads as two lines.
  • If the clipboard is unavailable the block selects the snippet instead, so the reader copies it with their own shortcut. Callers add no fallback of their own.
  • The copy button is built in. Never wrap the block in your own copy affordance or hand-roll a <pre>.
  • CodeBlock is atomic — one snippet. To switch languages or files, make CodeBlocks the children of a Tabs; to frame a group of steps, wrap them in a Card. Do not add a switcher to the block itself.
  • A header row appears when you pass a `filename` or a `language`; otherwise the copy button overlays the top-right.
  • Line numbers appear automatically for any multi-line snippet (the convention); single lines have none. Override with `lineNumbers={false}` (force off) or `lineNumbers` (force on).
  • The block sits on --background with a 1px border — intentionally unlike the borderless Card, so a snippet reads as a distinct inset panel.
  • Syntax highlighting (sugar-high) is on by default, tuned for JS/TS/JSX. Pass `highlight={false}` for prose or non-code text that would mis-tokenize (e.g. a generated agent prompt). The token palette lives in packages/ui css/code-block.css — tune it there, never per call.
  • Long lines scroll horizontally inside the block; the surrounding layout never scrolls sideways.