affectUI › Components › Text

Code Block

Code to read and copy – a header with the file name or language and a copy button, line numbers, highlighted lines, long lines that scroll inside and a small built-in colorizer.

Free and open source (MIT). Install: npx shadcn@latest add https://www.affectui.com/r/code-block.json · Import from @/components/ui/code-block

When to use

  • Showing code someone will copy: an install command, a config file, an API example, a snippet an agent wrote
  • Tool inputs and outputs, logs or JSON payloads that need to keep their exact spacing
  • Pointing at a few lines – highlightLines marks them, showLineNumbers lets people refer to them

When not to use

  • A single name or value inside a sentence – use an inline <code> or a Kbd chip for shortcuts
  • A secret someone copies once, like an API key – a read-only Text Field with a copy button fits better
  • Comparing two versions of code – use the Inline Diff
  • A whole tool call with its arguments and result – use the Tool Call Card

Usage

import { CodeBlock } from "@/components/ui/code-block";

export function ReviewerConfig() {
  return (
    <CodeBlock
      language="ts"
      filename="agents/reviewer.ts"
      showLineNumbers
      highlightLines={[8, 9]}
      code={`import { defineAgent } from "@acme/agents";

export const reviewer = defineAgent({
  name: "Code reviewer",
  model: "claude-opus",
  tools: ["github", "linear"],
  // Ask before anything leaves the repo
  approval: { required: true, timeout: "2h" },
  maxSteps: 24,
});`}
    />
  );
}

Props

NameTypeDefaultDescription
codestringRequired. The code – copied exactly as given; one trailing newline isn't shown as an empty line
languagestringts, tsx, js, jsx, json, bash, sh, python … – TypeScript / JavaScript, JSON, Bash and Python are colored, anything else is plain text. Named in the header when there is no filename
filenamestringShown in the header instead of the language; long names end in … with the full name as a tooltip
showLineNumbersbooleanfalseNumbers in front of every line – they stay in place while long lines scroll sideways and are left out when code is selected
highlightLinesnumber[]Lines to mark, counted from 1 – a light blue tint with a thin edge on the left
wrapbooleanfalseLong lines wrap instead of scrolling sideways
maxHeightnumber | stringAfter this height the code scrolls inside, e.g. 320 or "40vh"
copyablebooleantrueThe copy button; without it and without a filename or language there is no header
onCopy(code: string) => voidCalled after the code was copied, e.g. to show a toast
className / stylestring / CSSPropertiesOn the root <figure>

Keyboard

  • Tab: Moves to the copy button, then into the code when it scrolls
  • Enter / Space: Copies the code (on the copy button)
  • ← / → / ↑ / ↓: Scroll the code when it's focused

Accessibility

  • A <figure> with the header as its <figcaption>, the code in <pre><code>
  • The copy button is named Copy code, then Copied; a polite status also announces Copied
  • When the code scrolls it becomes a focusable region, so keyboard users can scroll it; when it fits it's not a tab stop
  • Line numbers are hidden from screen readers and can't be selected, so copying by hand gives clean code
  • Code always runs left to right, also in right-to-left pages; the file name follows its own direction
  • The ring shows only under keyboard focus (:focus-visible), never after a click

Responsive

  • Never wider than its container: long lines scroll inside the card (or wrap with wrap) instead of stretching the page
  • Touch screens get a bigger hit area around the copy button
  • Dark mode built in: switches when an ancestor (usually <html>) has the class dark or data-theme="dark"

Requirements

  • React 19

Related

  • Tool Call Card – An agent's tool call in one line – live timer, status and summary, folds open to highlighted arguments and result with copy, retry on errors and a group that sums them up
  • Inline Diff – AI edits to prose shown inline – struck and added words you accept or reject one by one, with keys, a popover and undo
  • AI Answer – Streamed answer with source cards, citation chips that preview their source, copy, regenerate, feedback and follow-ups
  • Text Field – One input for every form – label, hint and error in place, prefix and suffix, clear, show-password and copy buttons, a character count