CodeBlock

Server-rendered, syntax-highlighted code block with a language-label header and a copy button. Dual-theme via Shiki — same HTML for light + dark.

Install command

install
pnpm dlx @hex-core/cli add submit-button

TypeScript snippet

tsx
import { Button } from "@hex-core/components";

export function SubmitButton({ pending }: { pending: boolean }) {
  return (
    <Button type="submit" disabled={pending}>
      {pending ? "Saving…" : "Save changes"}
    </Button>
  );
}

Multi-snippet — component + registry entry + install

submit-button.tsx
import { Button } from "@hex-core/components";

export function SubmitButton({ pending }: { pending: boolean }) {
  return (
    <Button type="submit" disabled={pending}>
      {pending ? "Saving…" : "Save changes"}
    </Button>
  );
}
registry/items/submit-button.json
{
  "name": "submit-button",
  "category": "form",
  "props": [
    { "name": "pending", "type": "boolean", "required": true }
  ]
}
install
pnpm dlx @hex-core/cli add submit-button

Installation

pnpm
pnpm dlx @hex-core/cli add code-block

Inline TS sample

Explicit language overrides label inference.

tsx
<CodeBlock language="tsx" code={`<Button>Click</Button>`} />

API Reference

PropTypeDefaultDescription
coderequired
stringThe code to display. Plain text — no markdown fences.
label
stringHeader label (e.g. "pnpm", "tsx"). Inferred from `language` if omitted.
language
"bash" | "ts" | "tsx" | "js" | "jsx" | "json" | "css" | "html" | "md" | "py" | "text"Shiki grammar key. Overrides inference from `label`.
themes
object[object Object]Override the default theme pair. Keys: `light`, `dark` — values are Shiki theme IDs.
className
stringAdditional CSS classes on the outer card.

AI Guidance

When to use

Render any code snippet in docs, copy-to-clipboard install commands, or static AI chat output where server rendering is acceptable. Pair with Markdown's `components.pre` override to take over markdown code fences.

When not to use

Don't use for streaming chat where the code grows mid-render — async Server Components can't update token-by-token. Use Streamdown's built-in client CodeBlock for that.

Common mistakes

  • Passing markdown-fenced code (with ```) — strip the fences first
  • Forgetting that this is async — must be awaited or rendered as RSC
  • Using a Shiki theme that isn't bundled — fails with a runtime fetch error

Accessibility

Highlighted output is plain text inside a `<pre>` — screen readers read it normally. The copy button has its own `aria-label`. Add a meaningful `aria-label` on the wrapper if the label alone isn't descriptive.

Related components

Token budget: 320

Verified against @hex-core/components@1.12.0