Installation
Complete project setup first. Your configuration
must select react/radix and include your Design System ID.
pnpm exec frontfriend download code-block -f react --primitive radixReview dependencies reported by the downloader and keep your source changes in version control.
Usage
import {
CodeBlock,
CodeBlockHeader,
CodeBlockTitle,
CodeBlockActions,
CodeBlockCopyButton,
CodeBlockContent,
CodeBlockFooter,
} from "@/components/ui/code-block";
const code = 'const message = "Hello, Frontfriend";\n\nconsole.log(message);';
export default function CodeBlockExample() {
const source = code;
return (
<div style={{ width: "min(44rem, calc(100vw - 2rem))", maxWidth: "100%" }}>
<CodeBlock
variant="default"
size="default"
>
<CodeBlockHeader>
<CodeBlockTitle>example.ts</CodeBlockTitle>
<CodeBlockActions>
<CodeBlockCopyButton value={source} />
</CodeBlockActions>
</CodeBlockHeader>
<CodeBlockContent
wrap={false}
lineNumbers={false}
startLine={1}
aria-label="Editable code"
>
{source}
</CodeBlockContent>
<CodeBlockFooter>Plain text</CodeBlockFooter>
</CodeBlock>
</div>
);
} Compose a header, title, actions, content, lines, and footer. Pass the original text to the copy button. Line numbers and diff markers are display only. Copy feedback appears after the Clipboard promise resolves and resets after two seconds. Failed copies keep the Copy label. Use line numbers with wrapping to keep the gutter aligned. Give the focusable code area a useful title or accessible label. Code stays left-to-right inside a right-to-left page.
Syntax highlighting
Highlighting is optional. Plain code does not load Shiki. A supported language loads when first used. GitHub Light and Dark supply syntax colors; the design system controls surfaces, borders, and actions. Unsupported languages and failed language loads remain plain text. Token text is escaped by the framework. The diff language colors a diff; it does not set added or removed line variants.
Helper imports
Import highlightCode and loadHighlighter from @/components/ui/code-block/highlighter. The helpers stay separate from the UI entry. highlightCode(code, language) is async and returns one highlighted line per input line, or null for an unsupported language or a failed load. It works on the server and retains final newlines. loadHighlighter(language) returns a tokenizer with highlight(code, state?) for grammar-state continuation.
Import useHighlightedCode from @/components/ui/code-block/use-highlighted-code. Pass the current code and language strings. Render each returned line inside CodeBlockLine. The hook removes exactly one final newline, caches complete lines, and updates the last line as text arrives. The server renders plain lines until the hook mounts. For server rendering with colors, await highlightCode from its own subpath.
The copy button uses onClick. Other Button and native pre attributes are forwarded.
Replace a stock installation
Use --replace when the CLI reports a conflict with existing files. The install replaces code-block.tsx and delivers both helpers in the code-block folder. Update imports from @/lib/highlighter to @/components/ui/code-block/highlighter, and from @/hooks/use-highlighted-code to @/components/ui/code-block/use-highlighted-code. The old lib/highlighter.tsx and hooks/use-highlighted-code.ts files remain outside the install manifest. Remove them after all callers use the new paths.
Examples
Default
import { CodeBlock, CodeBlockContent } from "@/components/ui/code-block";
const code = 'const message = "Hello, Frontfriend";\n\nconsole.log(message);';
<div style={{ width: "min(44rem, calc(100vw - 2rem))", maxWidth: "100%" }}>
<CodeBlock>
<CodeBlockContent aria-label="Plain code">{code}</CodeBlockContent>
</CodeBlock>
</div>; Header And Footer
import {
CodeBlock,
CodeBlockHeader,
CodeBlockTitle,
CodeBlockActions,
CodeBlockCopyButton,
CodeBlockContent,
CodeBlockFooter,
} from "@/components/ui/code-block";
const code = 'const message = "Hello, Frontfriend";\n\nconsole.log(message);';
<div style={{ width: "min(44rem, calc(100vw - 2rem))", maxWidth: "100%" }}>
<CodeBlock>
<CodeBlockHeader>
<CodeBlockTitle>example.ts</CodeBlockTitle>
<CodeBlockActions>
<CodeBlockCopyButton value={code} />
</CodeBlockActions>
</CodeBlockHeader>
<CodeBlockContent aria-label="Example source">{code}</CodeBlockContent>
<CodeBlockFooter>TypeScript · Plain text</CodeBlockFooter>
</CodeBlock>
</div>; Floating Actions
import {
CodeBlock,
CodeBlockActions,
CodeBlockCopyButton,
CodeBlockContent,
} from "@/components/ui/code-block";
const code = 'const message = "Hello, Frontfriend";\n\nconsole.log(message);';
<div style={{ width: "min(44rem, calc(100vw - 2rem))", maxWidth: "100%" }}>
<CodeBlock>
<CodeBlockActions>
<CodeBlockCopyButton value={code} />
</CodeBlockActions>
<CodeBlockContent aria-label="Code with floating actions">
{code}
</CodeBlockContent>
</CodeBlock>
</div>; Small
import {
CodeBlock,
CodeBlockHeader,
CodeBlockTitle,
CodeBlockActions,
CodeBlockCopyButton,
CodeBlockContent,
CodeBlockFooter,
} from "@/components/ui/code-block";
const code = 'const message = "Hello, Frontfriend";\n\nconsole.log(message);';
<div style={{ width: "min(44rem, calc(100vw - 2rem))", maxWidth: "100%" }}>
<CodeBlock size="sm">
<CodeBlockHeader>
<CodeBlockTitle>compact.ts</CodeBlockTitle>
<CodeBlockActions>
<CodeBlockCopyButton value={code} />
</CodeBlockActions>
</CodeBlockHeader>
<CodeBlockContent lineNumbers aria-label="Compact code">
{code}
</CodeBlockContent>
<CodeBlockFooter>3 lines</CodeBlockFooter>
</CodeBlock>
</div>; Wrap
import { CodeBlock, CodeBlockContent } from "@/components/ui/code-block";
const longCode =
'const description = "A long line of plain text wraps inside the code block while each line number stays aligned with the first row of its content.";\nconsole.log(description);';
<div style={{ width: "min(44rem, calc(100vw - 2rem))", maxWidth: "100%" }}>
<CodeBlock>
<CodeBlockContent wrap aria-label="Wrapped code">
{longCode}
</CodeBlockContent>
</CodeBlock>
</div>; Line Numbers
import { CodeBlock, CodeBlockContent } from "@/components/ui/code-block";
const code = 'const message = "Hello, Frontfriend";\n\nconsole.log(message);';
<div style={{ width: "min(44rem, calc(100vw - 2rem))", maxWidth: "100%" }}>
<CodeBlock>
<CodeBlockContent lineNumbers aria-label="Numbered code">
{code}
</CodeBlockContent>
</CodeBlock>
</div>; Start Offset
import { CodeBlock, CodeBlockContent } from "@/components/ui/code-block";
const code = 'const message = "Hello, Frontfriend";\n\nconsole.log(message);';
<div style={{ width: "min(44rem, calc(100vw - 2rem))", maxWidth: "100%" }}>
<CodeBlock>
<CodeBlockContent
lineNumbers
startLine={10000}
aria-label="Code starting at line 10000"
>
{code}
</CodeBlockContent>
</CodeBlock>
</div>; Wrap And Numbers
import { CodeBlock, CodeBlockContent } from "@/components/ui/code-block";
const longCode =
'const description = "A long line of plain text wraps inside the code block while each line number stays aligned with the first row of its content.";\nconsole.log(description);';
<div style={{ width: "min(44rem, calc(100vw - 2rem))", maxWidth: "100%" }}>
<CodeBlock>
<CodeBlockContent
wrap
lineNumbers
startLine={98}
aria-label="Wrapped numbered code"
>
{longCode}
</CodeBlockContent>
</CodeBlock>
</div>; Diff Lines
import {
CodeBlock,
CodeBlockHeader,
CodeBlockTitle,
CodeBlockActions,
CodeBlockCopyButton,
CodeBlockContent,
CodeBlockLine,
} from "@/components/ui/code-block";
const diffCode =
"const config = {\n retries: 1,\n retries: 3,\n timeout: 2000,\n};\n";
<div style={{ width: "min(44rem, calc(100vw - 2rem))", maxWidth: "100%" }}>
<CodeBlock>
<CodeBlockHeader>
<CodeBlockTitle>configuration.diff</CodeBlockTitle>
<CodeBlockActions>
<CodeBlockCopyButton value={diffCode} />
</CodeBlockActions>
</CodeBlockHeader>
<CodeBlockContent lineNumbers aria-label="Configuration diff">
<CodeBlockLine>{"const config = {"}</CodeBlockLine>
<CodeBlockLine variant="removed">{" retries: 1,"}</CodeBlockLine>
<CodeBlockLine variant="added">{" retries: 3,"}</CodeBlockLine>
<CodeBlockLine variant="highlighted">{" timeout: 2000,"}</CodeBlockLine>
<CodeBlockLine>{"};"}</CodeBlockLine>
<CodeBlockLine />
</CodeBlockContent>
</CodeBlock>
</div>; Destructive
import {
CodeBlock,
CodeBlockHeader,
CodeBlockTitle,
CodeBlockActions,
CodeBlockCopyButton,
CodeBlockContent,
CodeBlockFooter,
} from "@/components/ui/code-block";
const errorCode =
"Error: Cannot find module ./config\n at build (build.ts:12:3)";
<div style={{ width: "min(44rem, calc(100vw - 2rem))", maxWidth: "100%" }}>
<CodeBlock variant="destructive">
<CodeBlockHeader>
<CodeBlockTitle>Build failed</CodeBlockTitle>
<CodeBlockActions>
<CodeBlockCopyButton value={errorCode} />
</CodeBlockActions>
</CodeBlockHeader>
<CodeBlockContent aria-label="Build error">{errorCode}</CodeBlockContent>
<CodeBlockFooter>Check the file path and try again.</CodeBlockFooter>
</CodeBlock>
</div>; Copy
import {
CodeBlock,
CodeBlockHeader,
CodeBlockTitle,
CodeBlockActions,
CodeBlockCopyButton,
CodeBlockContent,
} from "@/components/ui/code-block";
const code = 'const message = "Hello, Frontfriend";\n\nconsole.log(message);';
<div style={{ width: "min(44rem, calc(100vw - 2rem))", maxWidth: "100%" }}>
<CodeBlock>
<CodeBlockHeader>
<CodeBlockTitle>Copy example</CodeBlockTitle>
<CodeBlockActions>
<CodeBlockCopyButton value={code} />
</CodeBlockActions>
</CodeBlockHeader>
<CodeBlockContent lineNumbers aria-label="Code to copy">
{code}
</CodeBlockContent>
</CodeBlock>
</div>; Blank Lines
import { CodeBlock, CodeBlockContent } from "@/components/ui/code-block";
<div style={{ width: "min(44rem, calc(100vw - 2rem))", maxWidth: "100%" }}>
<CodeBlock>
<CodeBlockContent lineNumbers aria-label="Code with blank lines">
{"first\n\nlast\n\n"}
</CodeBlockContent>
</CodeBlock>
</div>; Right To Left
import {
CodeBlock,
CodeBlockHeader,
CodeBlockTitle,
CodeBlockActions,
CodeBlockCopyButton,
CodeBlockContent,
CodeBlockFooter,
} from "@/components/ui/code-block";
const code = 'const message = "Hello, Frontfriend";\n\nconsole.log(message);';
<div style={{ width: "min(44rem, calc(100vw - 2rem))", maxWidth: "100%" }}>
<div dir="rtl">
<CodeBlock>
<CodeBlockHeader>
<CodeBlockTitle>مثال الشفرة</CodeBlockTitle>
<CodeBlockActions>
<CodeBlockCopyButton value={code} />
</CodeBlockActions>
</CodeBlockHeader>
<CodeBlockContent lineNumbers aria-label="Left-to-right code">
{code}
</CodeBlockContent>
<CodeBlockFooter>نص عادي</CodeBlockFooter>
</CodeBlock>
</div>
</div>; Highlighted
import { useHighlightedCode } from "@/components/ui/code-block/use-highlighted-code";
import {
CodeBlock,
CodeBlockHeader,
CodeBlockTitle,
CodeBlockActions,
CodeBlockCopyButton,
CodeBlockContent,
CodeBlockLine,
CodeBlockFooter,
} from "@/components/ui/code-block";
function HighlightedFile({
value,
language,
title,
wrap = false,
}: {
value: string;
language: string;
title: string;
wrap?: boolean;
}) {
const lines = useHighlightedCode(value, language);
return (
<CodeBlock>
<CodeBlockHeader>
<CodeBlockTitle>{title}</CodeBlockTitle>
<CodeBlockActions>
<CodeBlockCopyButton value={value} />
</CodeBlockActions>
</CodeBlockHeader>
<CodeBlockContent lineNumbers wrap={wrap} aria-label={title}>
{lines.map((line, index) => (
<CodeBlockLine key={index}>{line}</CodeBlockLine>
))}
</CodeBlockContent>
<CodeBlockFooter>{language}</CodeBlockFooter>
</CodeBlock>
);
}
const highlightedSource =
'// Fetch one user and keep the response typed.\n// The caller handles network errors.\ntype User = { id: number; name: string };\n\n/** Read the user record from the API. */\nexport async function getUser(id: number): Promise<User> {\n // Use the same endpoint for cached and fresh records.\n const response = await fetch(`/api/users/${id}`);\n if (!response.ok) {\n throw new Error("User not found");\n }\n\n // Keep JSON parsing in the typed request function.\n return response.json();\n}';
<div style={{ width: "min(44rem, calc(100vw - 2rem))", maxWidth: "100%" }}>
<HighlightedFile
value={highlightedSource}
language="typescript"
title="users.ts"
wrap={false}
/>
</div>; Server Helper
import { highlightCode } from "@/components/ui/code-block/highlighter";
import {
CodeBlock,
CodeBlockHeader,
CodeBlockTitle,
CodeBlockActions,
CodeBlockCopyButton,
CodeBlockContent,
CodeBlockLine,
CodeBlockFooter,
} from "@/components/ui/code-block";
import * as React from "react";
const highlightedSource =
'// Fetch one user and keep the response typed.\n// The caller handles network errors.\ntype User = { id: number; name: string };\n\n/** Read the user record from the API. */\nexport async function getUser(id: number): Promise<User> {\n // Use the same endpoint for cached and fresh records.\n const response = await fetch(`/api/users/${id}`);\n if (!response.ok) {\n throw new Error("User not found");\n }\n\n // Keep JSON parsing in the typed request function.\n return response.json();\n}';
function ServerHelperExample() {
const [lines, setLines] = React.useState<React.ReactNode[] | null>(null);
React.useEffect(() => {
let active = true;
void highlightCode(highlightedSource, "typescript").then((next) => {
if (active) setLines(next);
});
return () => {
active = false;
};
}, []);
return (
<CodeBlock>
<CodeBlockHeader>
<CodeBlockTitle>Full-file helper</CodeBlockTitle>
<CodeBlockActions>
<CodeBlockCopyButton value={highlightedSource} />
</CodeBlockActions>
</CodeBlockHeader>
<CodeBlockContent lineNumbers aria-label="Full highlighted source">
{(lines ?? highlightedSource.split("\n")).map((line, index) => (
<CodeBlockLine key={index}>{line}</CodeBlockLine>
))}
</CodeBlockContent>
<CodeBlockFooter>
highlightCode returns one node array per line.
</CodeBlockFooter>
</CodeBlock>
);
}
<div style={{ width: "min(44rem, calc(100vw - 2rem))", maxWidth: "100%" }}>
<ServerHelperExample />
</div>; Streaming
import { useHighlightedCode } from "@/components/ui/code-block/use-highlighted-code";
import { Button } from "@/components/ui/button";
import {
CodeBlock,
CodeBlockHeader,
CodeBlockTitle,
CodeBlockActions,
CodeBlockCopyButton,
CodeBlockContent,
CodeBlockLine,
CodeBlockFooter,
} from "@/components/ui/code-block";
import * as React from "react";
const highlightedSource =
'// Fetch one user and keep the response typed.\n// The caller handles network errors.\ntype User = { id: number; name: string };\n\n/** Read the user record from the API. */\nexport async function getUser(id: number): Promise<User> {\n // Use the same endpoint for cached and fresh records.\n const response = await fetch(`/api/users/${id}`);\n if (!response.ok) {\n throw new Error("User not found");\n }\n\n // Keep JSON parsing in the typed request function.\n return response.json();\n}';
export default function CodeBlockExample() {
const [length, setLength] = React.useState(58);
const [running, setRunning] = React.useState(false);
const value = highlightedSource.slice(0, length);
const lines = useHighlightedCode(value, "typescript");
React.useEffect(() => {
if (!running) return;
const timer = setInterval(
() =>
setLength((current) => Math.min(current + 3, highlightedSource.length)),
45,
);
return () => clearInterval(timer);
}, [running]);
React.useEffect(() => {
if (length === highlightedSource.length) setRunning(false);
}, [length]);
return (
<div
style={{
display: "grid",
gap: "1rem",
width: "min(44rem, calc(100vw - 2rem))",
maxWidth: "100%",
}}
>
<form
style={{ display: "flex", gap: "0.5rem" }}
onSubmit={(event) => {
event.preventDefault();
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
setLength(highlightedSource.length);
setRunning(false);
return;
}
if (length === highlightedSource.length) setLength(0);
setRunning((current) => !current);
}}
>
<Button type="submit" variant="outline">
{running ? "Pause stream" : "Start stream"}
</Button>
</form>
<CodeBlock>
<CodeBlockHeader>
<CodeBlockTitle>Generated users.ts</CodeBlockTitle>
<CodeBlockActions>
<CodeBlockCopyButton value={value} />
</CodeBlockActions>
</CodeBlockHeader>
<CodeBlockContent lineNumbers aria-label="Streamed TypeScript">
{lines.map((line, index) => (
<CodeBlockLine key={index}>{line}</CodeBlockLine>
))}
</CodeBlockContent>
<CodeBlockFooter>
{running
? "Receiving code…"
: length === highlightedSource.length
? "Complete"
: "Paused"}
</CodeBlockFooter>
</CodeBlock>
</div>
);
} Multiple Languages
import { useHighlightedCode } from "@/components/ui/code-block/use-highlighted-code";
import {
CodeBlock,
CodeBlockHeader,
CodeBlockTitle,
CodeBlockActions,
CodeBlockCopyButton,
CodeBlockContent,
CodeBlockLine,
CodeBlockFooter,
} from "@/components/ui/code-block";
function HighlightedFile({
value,
language,
title,
wrap = false,
}: {
value: string;
language: string;
title: string;
wrap?: boolean;
}) {
const lines = useHighlightedCode(value, language);
return (
<CodeBlock>
<CodeBlockHeader>
<CodeBlockTitle>{title}</CodeBlockTitle>
<CodeBlockActions>
<CodeBlockCopyButton value={value} />
</CodeBlockActions>
</CodeBlockHeader>
<CodeBlockContent lineNumbers wrap={wrap} aria-label={title}>
{lines.map((line, index) => (
<CodeBlockLine key={index}>{line}</CodeBlockLine>
))}
</CodeBlockContent>
<CodeBlockFooter>{language}</CodeBlockFooter>
</CodeBlock>
);
}
const highlightedSource =
'// Fetch one user and keep the response typed.\n// The caller handles network errors.\ntype User = { id: number; name: string };\n\n/** Read the user record from the API. */\nexport async function getUser(id: number): Promise<User> {\n // Use the same endpoint for cached and fresh records.\n const response = await fetch(`/api/users/${id}`);\n if (!response.ok) {\n throw new Error("User not found");\n }\n\n // Keep JSON parsing in the typed request function.\n return response.json();\n}';
const pythonSource =
'from dataclasses import dataclass\n\n@dataclass\nclass User:\n id: int\n name: str\n\ndef greet(user: User) -> str:\n return f"Hello, {user.name}!"\n\nusers = [User(1, "Ada"), User(2, "Lin")]\nfor user in users:\n print(greet(user))';
const jsonSource =
'{\n "service": "users",\n "version": 2,\n "endpoints": [\n { "method": "GET", "path": "/api/users/:id" },\n { "method": "POST", "path": "/api/users" }\n ],\n "cache": {\n "enabled": true,\n "ttl": 300\n }\n}';
<div
style={{
display: "grid",
gap: "1rem",
width: "min(48rem, calc(100vw - 2rem))",
maxWidth: "100%",
}}
>
<HighlightedFile
value={highlightedSource}
language="typescript"
title="users.ts"
/>
<HighlightedFile value={pythonSource} language="python" title="greet.py" />
<HighlightedFile value={jsonSource} language="json" title="service.json" />
</div>; Unsupported Language
import { useHighlightedCode } from "@/components/ui/code-block/use-highlighted-code";
import {
CodeBlock,
CodeBlockHeader,
CodeBlockTitle,
CodeBlockActions,
CodeBlockCopyButton,
CodeBlockContent,
CodeBlockLine,
CodeBlockFooter,
} from "@/components/ui/code-block";
function HighlightedFile({
value,
language,
title,
wrap = false,
}: {
value: string;
language: string;
title: string;
wrap?: boolean;
}) {
const lines = useHighlightedCode(value, language);
return (
<CodeBlock>
<CodeBlockHeader>
<CodeBlockTitle>{title}</CodeBlockTitle>
<CodeBlockActions>
<CodeBlockCopyButton value={value} />
</CodeBlockActions>
</CodeBlockHeader>
<CodeBlockContent lineNumbers wrap={wrap} aria-label={title}>
{lines.map((line, index) => (
<CodeBlockLine key={index}>{line}</CodeBlockLine>
))}
</CodeBlockContent>
<CodeBlockFooter>{language}</CodeBlockFooter>
</CodeBlock>
);
}
<div style={{ width: "min(44rem, calc(100vw - 2rem))", maxWidth: "100%" }}>
<HighlightedFile
value={'TASK deploy\n WHEN checks = passed\n THEN publish "preview"'}
language="custom-dsl"
title="deploy.workflow"
/>
</div>; Highlighted Diff
import { useHighlightedCode } from "@/components/ui/code-block/use-highlighted-code";
import {
CodeBlock,
CodeBlockHeader,
CodeBlockTitle,
CodeBlockActions,
CodeBlockCopyButton,
CodeBlockContent,
CodeBlockLine,
CodeBlockFooter,
} from "@/components/ui/code-block";
const highlightedDiffSource =
"const config = {\n retries: 1, // Stop after the first failure.\n retries: 3, // Retry temporary failures.\n timeout: 2000, // Keep the request deadline.\n};\n";
function HighlightedDiffExample() {
const lines = useHighlightedCode(highlightedDiffSource, "typescript");
return (
<CodeBlock>
<CodeBlockHeader>
<CodeBlockTitle>config.ts</CodeBlockTitle>
<CodeBlockActions>
<CodeBlockCopyButton value={highlightedDiffSource} />
</CodeBlockActions>
</CodeBlockHeader>
<CodeBlockContent lineNumbers aria-label="Highlighted configuration diff">
{lines.map((line, index) => (
<CodeBlockLine
key={index}
variant={
index === 1
? "removed"
: index === 2
? "added"
: index === 3
? "highlighted"
: "default"
}
>
{line}
</CodeBlockLine>
))}
</CodeBlockContent>
<CodeBlockFooter>
Syntax colors and explicit line variants.
</CodeBlockFooter>
</CodeBlock>
);
}
<div style={{ width: "min(44rem, calc(100vw - 2rem))", maxWidth: "100%" }}>
<HighlightedDiffExample />
</div>; API reference
Frontfriend-owned props. Native HTML and inherited primitive props remain documented by Radix UI.
highlightCode
| Prop | Type | Default | Description |
|---|---|---|---|
code | string | — | Source text to highlight. |
language | string | — | A supported language name or alias. Returns null for an unsupported language or a failed load. |
loadHighlighter
| Prop | Type | Default | Description |
|---|---|---|---|
language | string | — | A supported language name or alias. Returns null for an unsupported language or a failed load. |
useHighlightedCode
| Prop | Type | Default | Description |
|---|---|---|---|
language | string | — | A supported language name or alias. Unsupported names return plain text in the hook. |
value | string | — | Source text to highlight. |
CodeBlock
| Prop | Type | Default | Description |
|---|---|---|---|
size | "default" | "sm" | "default" | The code text size and spacing. |
variant | "default" | "destructive" | "default" | The color style of the block. |
CodeBlockContent
| Prop | Type | Default | Description |
|---|---|---|---|
lineNumbers | boolean | false | Show line numbers. Numbers are excluded from copied text. |
startLine | number | 1 | The first line number. |
wrap | boolean | false | Wrap long lines within the block. |
CodeBlockCopyButton
| Prop | Type | Default | Description |
|---|---|---|---|
onClick | React.ComponentProps<typeof Button>["onClick"] | — | Called when the copy button is clicked. Prevent the default event to cancel copying. |
size | React.ComponentProps<typeof Button>["size"] | "icon-xs" | The inherited Button size. |
value | string | — | The exact text to copy. Required. |
variant | React.ComponentProps<typeof Button>["variant"] | "ghost" | The inherited Button style. |
CodeBlockLine
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "default" | "added" | "removed" | "highlighted" | "default" | The style of this line. Diff markers are excluded from copied text. |
Configuration determines the actual classes and available styling hooks. See Theming & component configuration before introducing a repeated local override.