Code block

Present code with legible hierarchy and copy access.

contentdeveloper
Preview
Code block preview
counter.tsxtsx
export function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You pressed {count} times.</p>
      <button onClick={() => setCount(count + 1)}>
        Press me
      </button>
    </div>
  );
}

When to use

  • Documentation snippets and install commands with a copy button.
  • Long files that should collapse to a few lines with Show all, via maxLines.

When not to use

  • Use copy-button alone for a one-line value such as an API key.
  • Use text-stream for code arriving from an AI response in progress.
  • Use a full highlighter library when you need many languages.

shadcn CLI

Also installs (2)

  • manicat-foundation
  • copy-button
Manual install(+)
registry.jsonjson
{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "code-block",
  "type": "registry:ui",
  "title": "Code block",
  "description": "Present code with legible hierarchy and copy access.",
  "categories": [
    "data"
  ],
  "dependencies": [
    "lucide-react",
    "motion"
  ],
  "registryDependencies": [
    "https://manicat.viraza.net/r/manicat-foundation.json",
    "https://manicat.viraza.net/r/copy-button.json"
  ],
  "files": [
    {
      "path": "registry/components/code-block/code-block.tsx",
      "type": "registry:component",
      "target": "@components/manicat/code-block/code-block.tsx"
    },
    {
      "path": "registry/components/code-block/code-block.module.css",
      "type": "registry:component",
      "target": "@components/manicat/code-block/code-block.module.css"
    },
    {
      "path": "registry/components/copy-button/copy-button.tsx",
      "type": "registry:component",
      "target": "@components/manicat/copy-button/copy-button.tsx"
    },
    {
      "path": "registry/components/copy-button/copy-button.module.css",
      "type": "registry:component",
      "target": "@components/manicat/copy-button/copy-button.module.css"
    },
    {
      "path": "lib/use-copy-feedback.ts",
      "type": "registry:lib",
      "target": "@components/manicat/lib/use-copy-feedback.ts"
    }
  ],
  "docs": "Docs and live preview: https://uiarc.dev/components/code-block",
  "meta": {
    "tier": "free",
    "kind": "component",
    "docs": "https://manicat.viraza.net/components/code-block",
    "markdown": "https://uiarc.dev/components/code-block/markdown",
    "tags": [
      "content",
      "developer"
    ]
  }
}

Usage

Install the component, then copy this into your app. Change the content and the props to fit your screen.

example.tsxtsx
"use client";

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

export function CodeBlockExample() {
  return (
    <CodeBlock
      code={`export function Counter() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You pressed {count} times.</p>
      <button onClick={() => setCount(count + 1)}>
        Press me
      </button>
    </div>
  );
}`}
      filename="counter.tsx"
      language="tsx"
    />
  );
}

Examples

Real screens rather than isolated props. Switch to Code to copy a whole example into your project.

Installation snippet A code card with a file name and syntax highlighting.

Installation snippet A code card with a file name and syntax highlighting. preview
counter.tsxtsx
export function Counter() {
  const [count, setCount] = useState(0);

  return (
    <button onClick={() => setCount(count + 1)}>
      You pressed {count} times
    </button>
  );
}

Keyboard interactions

KeysAction
TabFocuses the copy button, the scrollable source, and the expand toggle.
Enter / SpaceCopies the code or toggles the expanded state.

Accessibility

  • The block is a section labelled like "hello.ts source code"; the pre is focusable so keyboard users can scroll it.
  • The expand toggle uses aria-expanded and aria-controls pointing at the source.
  • Copy feedback comes from copy-button.

Motion

  • Expanding or collapsing springs the source height; new code fades up in place.
  • The toggle label rolls and its chevron rotates.
  • Reduced motion snaps height and swaps text without movement.

Responsive behavior

  • Long lines scroll horizontally inside the block, never the page.
  • Below 420px the padding and font shrink and the copy button becomes icon-only.

Performance

  • The built-in highlighter is a small regex pass with no language bundles.
  • ResizeObservers measure the source for the height spring; many blocks on one page each run their own.

Notes for AI

  • Use for documentation snippets and install commands. The highlighter is lightweight; use a full highlighter for many languages.
  • Set maxLines for long files so pages stay scannable.