Code Block
Shiki highlighting, line numbers, copy, and scroll area for long snippets. Not tied to Markdown.
Private Registry
This component is distributed only from registry.private.json (Bearer token). It is not in the public registry.json. Configure @f-ui-private as in the data table docs, then install with @f-ui-private/code-block.
The code-block registry item provides CodeBlock: syntax highlighting (Shiki), optional chrome (title bar), line numbers with a sticky gutter on horizontal scroll, optional word wrap, copy, a spinner loading state while Shiki initializes, and a scrollable body for long files. Use it anywhere you need a polished code viewer; markdown-renderer can compose it for fenced blocks.
For rendered diagram previews (image view, zoom, pan, export), use the dedicated Mermaid Renderer component—not CodeBlock alone.
Installation
1. Configure components.json
Add @f-ui-private (same as Data Table).
2. Install
REGISTRY_TOKEN=xxx pnpm dlx shadcn@latest add @f-ui-private/code-blockREGISTRY_TOKEN=xxx npx shadcn@latest add @f-ui-private/code-blockREGISTRY_TOKEN=xxx yarn dlx shadcn@latest add @f-ui-private/code-blockREGISTRY_TOKEN=xxx bun x shadcn@latest add @f-ui-private/code-blockregistryDependencies: none. Runtime: shiki, next-themes (for light/dark theme alignment).
Contributors
Local build: pnpm registry:build:private — install from .registry-private/r/code-block.json.
Usage
import { CodeBlock } from "@/components/f-ui/code-block/code-block";
export function Example() {
return (
<CodeBlock
source={'console.log("hi")'}
language="ts"
title="example.ts"
/>
);
}Demos
Minimal (Default)
"use client";
import { CodeBlock } from "@/components/f-ui/code-block/code-block";
import { HONO_SAMPLE } from "@/demos/code-block/samples";
export function CodeBlockMinimalDemo() {
return <CodeBlock source={HONO_SAMPLE} language="ts" />;
}Chrome + Line Numbers
"use client";
import { CodeBlock } from "@/components/f-ui/code-block/code-block";
import { HONO_SAMPLE } from "@/demos/code-block/samples";
export function CodeBlockChromeLineNumbersDemo() {
return (
<CodeBlock
source={HONO_SAMPLE}
language="ts"
title="server.ts"
chrome
lineNumbers
copyStyle="always"
/>
);
}Long Lines (Sticky Gutter on Horizontal Scroll)
"use client";
import { CodeBlock } from "@/components/f-ui/code-block/code-block";
import { LONG_LINE_ROUTER_SAMPLE } from "@/demos/code-block/samples";
/** Long lines: sticky line-number gutter while code scrolls horizontally. */
export function CodeBlockStickyGutterDemo() {
return (
<CodeBlock
source={LONG_LINE_ROUTER_SAMPLE}
language="ts"
title="router.ts"
chrome
lineNumbers
copyStyle="always"
/>
);
}Word Wrap + Line Numbers
"use client";
import { CodeBlock } from "@/components/f-ui/code-block/code-block";
import { LONG_LINE_ROUTER_SAMPLE } from "@/demos/code-block/samples";
export function CodeBlockWordWrapDemo() {
return (
<CodeBlock
source={LONG_LINE_ROUTER_SAMPLE}
language="ts"
title="router.ts"
chrome
lineNumbers
wordWrap
copyStyle="always"
/>
);
}Loading (Shiki Initializing)
The demo below sets loading so the spinner is visible without reimplementing the component shell.
Pass loading to show the same spinner the component uses while Shiki initializes—no duplicate markup.
import { CodeBlock } from "@/components/f-ui/code-block/code-block"
const SOURCE = 'console.log("hello")'
/** Uses `loading` so the doc demo does not duplicate CodeBlock internals. */
export function CodeBlockLoadingDemo() {
return (
<div className="space-y-3">
<p className="text-muted-foreground text-sm">
Pass <code className="rounded bg-muted px-1 py-0.5 font-mono text-xs">loading</code> to
show the same spinner the component uses while Shiki initializes—no duplicate markup.
</p>
<CodeBlock
source={SOURCE}
language="ts"
title="example.ts"
chrome
loading
/>
</div>
)
}Mermaid (Highlighted Source)
CodeBlock with language="mermaid" behaves like any other language: Shiki highlighting, copy, scroll, and optional chrome or line numbers.
Preview vs. Source Only
This shows syntax-highlighted Mermaid text only. For an interactive diagram preview (Image/Code toggle, toolbar, fullscreen), use Mermaid Renderer.
"use client";
import { CodeBlock } from "@/components/f-ui/code-block/code-block";
import { MERMAID_SAMPLE } from "@/demos/code-block/samples";
export function CodeBlockMermaidDemo() {
return <CodeBlock source={MERMAID_SAMPLE} language="mermaid" />;
}API
| Prop | Type | Description |
|---|---|---|
source | string | Raw source (copied on Copy). |
language | string | Shiki language id; omit for plain monospace. |
title | string | Header label when chrome is on; overrides language in the header. |
chrome | boolean | Show title bar (default false). |
lineNumbers | boolean | Show gutter (default false). |
lineStart | number | First line number (default 1). |
wordWrap | boolean | Soft-wrap long lines (default false). |
showCopy | boolean | Show copy control (default true). |
copyStyle | "hover" | "always" | Copy placement (default hover). |
maxHeightClassName | string | Tailwind class for scroll region height (default max-h-[min(70vh,28rem)]). |
className | string | Outer container. |
classNames | CodeBlockClassNames | Optional slots: root, header, titleRow, scroll, body, pre. |
loading | boolean | If true, forces the Shiki loading UI (spinner). For demos or stories; normally omit and let the block load Shiki on its own. |
When language is set and Shiki is still loading, the block shows a centered spinner only (screen-reader text for status)—no visible label and no unstyled source text.