Code Block
Highlighted code with file tabs, line numbers, lit lines, diffs, wrap and copy. Built-in tokenizer, no dependencies.
Built on Copy Button and Icons.
Installation
npx shadcn@latest add https://neonkit.heyaadi.com/r/code-block.jsonUsage
import { CodeBlock } from "@/components/ui/code-block"
<CodeBlock filename="app/page.tsx" code={source} highlight={[3, 4]} />Examples
Diff
diff reads a leading + or - on each line. Copy gives you the file as it reads after the change, without the removed lines or the markers.
Shell, CSS and JSON
The built-in tokenizer covers JS, TS, JSX, TSX, HTML, JSON, CSS and shell. startLine numbers an excerpt from where it sits in the file.
Max height and wrap
Past maxHeight the body scrolls and the line numbers stay put. The wrap toggle folds long lines instead of scrolling sideways.
Without a header
header={false} for one-liners in prose. Copy appears on hover and on keyboard focus.
API reference
CodeBlock
Renders a div and accepts every native div attribute.
| Prop | Type | Default |
|---|---|---|
code | stringThe source. Ignored when files is set. A trailing newline is dropped. | None |
language | stringtsx, ts, jsx, js, html, json, css, bash, sh or diff. Other values render as plain text with their name in the header. | from filename |
filename | stringShown in the header with its directories dimmed. | None |
files | CodeBlockFile[]{ filename, code, language?, highlight?, diff?, startLine? } per tab. The tab value is the filename. | None |
value | stringControlled active file. | None |
defaultValue | stringInitial file when uncontrolled. | first file |
onValueChange | (filename: string) => voidCalled when another tab is chosen. | None |
highlight | (number | [number, number])[]Line numbers to light, as they're displayed. [3, 4] or [[3, 9]] for a range. | None |
diff | booleanTreat a leading + or - as added or removed. | false |
lineNumbers | booleanShow the line number gutter. | true |
startLine | numberNumber of the first line. | 1 |
wrap | booleanControlled word wrap. | None |
defaultWrap | booleanInitial wrap when uncontrolled. | false |
onWrapChange | (wrap: boolean) => voidCalled when the toggle is pressed. | None |
wrapToggle | booleanShow the wrap toggle in the header. | true |
copyable | booleanShow the copy button. | true |
maxHeight | numberThe body scrolls past this. Numbers are pixels. | None |
header | booleanHide the header; copy floats in the corner instead. | true |
color | NeonColorPalette name or hex. Token colors are derived from it. | inherited |
tokenize
The tokenizer on its own: tokenize(code, language) returns [kind, text] pairs, for rendering code somewhere else.
| Prop | Type | Default |
|---|---|---|
kind | CodeTokenKindkeyword, string, number, comment, function, type, property, punctuation, tag, attr, variable, prompt or plain. | None |
Accessibility
- Highlighting runs in render with no effects, so the server sends colored HTML and nothing shifts on hydration.
- Token colors are mixed from --neon and stay above 4.5:1 on the block's background for every palette color.
- The code area is a focusable region named after the file, so keyboard users can scroll it with the arrow keys.
- File tabs follow the tabs pattern: one Tab stop, arrow keys and Home/End move and select.
- Added and removed lines carry a hidden 'Added:' or 'Removed:' prefix for screen readers, left out of copied text.
- Line numbers and diff markers can't be selected, so copying by hand gives clean code.