Code Block
A syntax-highlighted code block with a copy button, a built-in lightweight tokenizer, and a line-by-line reveal animation.
A zero-dependency syntax-highlighted code block: it ships its own regex tokenizer (no shiki or prism required) and supports a filename header bar, line numbers, highlighting specific lines, one-click copy, and a line-by-line staggered fade in.
Bring this into your project
Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.
npx webberui@latest add code-block.enCode Block is a React syntax highlighting code block component built with Tailwind CSS and Motion, with lucide-react icons for the copy button. Highlighting is handled by a character-by-character tokenizer inside the file, so you do not need to install a separate highlighting package.
Playground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<CodeBlock/>
The complete example includes the preview layout and data. Install the component first, then paste this file into your project.
When to use
- Install commands and API call samples on a product site or landing page.
- Short snippets in blog posts, technical articles or changelogs.
- Step-by-step tutorials, using highlighted lines to mark what changed in each step.
- "Integration settings" pages in a SaaS dashboard showing webhook samples or SDK setup code.
Installation
npx webberui@latest add https://webberui.com/r/code-block.en.jsonOr, once registries are configured in components.json, install it as @webberui/code-block.
Usage
import { CodeBlock } from "@/components/ui/code-block";
<CodeBlock
code={`const hello = "world";`}
language="tsx"
filename="example.tsx"
showLineNumbers
/>Supported language keywords: tsx, jsx, ts, js, python, bash, css, json, html. An unknown language falls back to a generic mode that still highlights strings, comments, and numbers.
Examples
Read a file in a Server Component
The component only needs a code string, so a Next.js Server Component can read an example file with fs and pass it to CodeBlock.
// app/docs/setup/page.tsx
import { readFile } from "node:fs/promises";
import { CodeBlock } from "@/components/ui/code-block";
export default async function SetupPage() {
const code = await readFile("examples/client.ts", "utf8");
return (
<CodeBlock code={code} language="ts" filename="client.ts" showLineNumbers />
);
}Tutorial step with highlighted lines
highlightLines marks key lines by 1-based line number, and traffic adds a window header with red, yellow and green dots.
<CodeBlock
language="tsx"
filename="app/layout.tsx"
traffic
showLineNumbers
highlightLines={[2, 7]}
code={`import "./globals.css";
import { Toaster } from "@/components/ui/toaster";
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}<Toaster /></body>
</html>
);
}`}
/>Long output with a height limit and no animation
For long terminal output or config files, maxHeight makes the content area scroll and animate={false} renders it without the line-by-line fade.
<CodeBlock
language="bash"
filename="Terminal"
animate={false}
maxHeight={240}
code={deployLog}
/>Props
| Prop | Type | Default | Description |
|---|---|---|---|
code | string | — | The code string to display |
language | string | "tsx" | Language tag, which decides the keyword and comment syntax |
filename | string | — | Filename/title shown on the left of the header bar |
showLineNumbers | boolean | false | Whether to show line numbers |
highlightLines | number[] | [] | Line numbers to highlight (1-based), given a background tint |
copy | boolean | true | Whether to show the copy button |
traffic | boolean | false | Show macOS-style red/yellow/green dots in the header bar |
animate | boolean | true | Stagger a line-by-line fade in when it enters the viewport |
maxHeight | number | — | Maximum height of the content area (px); beyond it, the area scrolls |
Accessibility
- When the user has "reduce motion" enabled at the system level, it renders statically without applying the line-by-line animation
- The copy button carries an
aria-label, and after a successful copy it transitions smoothly between the copy and check icons - The first render matches SSR and the animation is only enabled after mount, which avoids a hydration mismatch
FAQ
Does it work with the Next.js App Router?
Yes. The file starts with "use client", so import it from a Server Component page as usual, and pass strings you read on the server straight into code. The first render matches the server output and animation is enabled after mount.
Which languages are supported?
language recognizes tsx, jsx, ts, js, python (py), bash (sh, shell, zsh), css (scss), json and html (xml). Any other value falls back to JavaScript-like rules that still highlight strings, comments and numbers.
How do I change the highlight colors?
Token colors live in the TOKEN_CLASS object in the source; each entry is a set of Tailwind classes including dark: variants, so edit them there. Override the frame and background with className.
What does the copy button copy?
It copies code with trailing newlines removed. On success the icon switches to a check mark and reverts after 2 seconds. If the browser blocks clipboard access (for example outside HTTPS), the component skips silently without throwing.
What are the dependencies?
motion, lucide-react, clsx and tailwind-merge; highlighting itself needs no extra package. If you prefer not to use the CLI, copy the source from the Manual tab in Installation.