CodeBlock
Syntax-highlighted code block backed by Shiki with dual-theme support, line numbers, line highlighting, and a copy button.
Renders a semantic <pre><code> element; copy button (if enabled) is keyboard-focusable with an accessible label and a success state.
import { CodeBlock } from '@arshad-shah/cynosure-react/code-block';
const snippet = `// Debounce helper
export const debounce = (fn, wait = 200) => {
let id;
return (...args) => {
clearTimeout(id);
id = setTimeout(() => fn(...args), wait);
};
};
`;
export default function Example() {
return <CodeBlock language="tsx">{snippet}</CodeBlock>;
}
Language
Section titled “Language”Pass a Shiki language identifier (tsx, bash, json, python, …) to opt into syntax highlighting. The default "text" skips Shiki entirely and renders plain pre-formatted text.
import { CodeBlock } from '@arshad-shah/cynosure-react/code-block';
const bash = `pnpm add @arshad-shah/cynosure-react
pnpm add @arshad-shah/cynosure-tokens
`;
export default function Example() {
return <CodeBlock language="bash">{bash}</CodeBlock>;
}
Line numbers and highlighting
Section titled “Line numbers and highlighting”Combine showLineNumbers with highlightLines to draw attention to a specific region of the snippet.
import { CodeBlock } from '@arshad-shah/cynosure-react/code-block';
const snippet = `import { Button } from "@arshad-shah/cynosure-react/code-block";
export function SaveButton() {
return (
<Button variant="solid" colorScheme="accent">
Save changes
</Button>
);
}
`;
export default function Example() {
return (
<CodeBlock language="tsx" showLineNumbers highlightLines={[4, 5, 6]}>
{snippet}
</CodeBlock>
);
}
Copy button
Section titled “Copy button”Set copyable to render a copy-to-clipboard button in the header. The label flips to “Copied” with a check icon while the success state is live.
import { CodeBlock } from '@arshad-shah/cynosure-react/code-block';
const snippet = `curl -fsSL https://cynosure.dev/install.sh | bash
`;
export default function Example() {
return (
<CodeBlock language="bash" copyable>
{snippet}
</CodeBlock>
);
}
With filename
Section titled “With filename”Pass filename (string or any ReactNode) to display a label in the header instead of the language tag.
import { CodeBlock } from '@arshad-shah/cynosure-react/code-block';
const snippet = `{
"name": "my-app",
"version": "0.1.0",
"private": true
}
`;
export default function Example() {
return (
<CodeBlock language="json" filename="package.json" copyable showLineNumbers>
{snippet}
</CodeBlock>
);
}
Accessibility
Section titled “Accessibility”- Wraps highlighted code in a semantic
<pre><code>pair (or Shiki’s pre-rendered HTML when provided). - The copy button is a real
<button>witharia-labelthat flips between “Copy code” and “Copied”. - Theming follows the active
data-themevia dual-theme CSS variables — contrast stays WCAG AA in both modes. - Long snippets stay inside an internal scroll region when
maxHeightis set, so they never break page layout. - Plain (
language="text") blocks remain selectable and readable by line.
Recipes
Section titled “Recipes”- Pass
htmldirectly when you have pre-rendered Shiki output (SSR, MDX, custom highlighters). - Pair
showLineNumberswithhighlightLines={[3, 4]}to spotlight a fix or diff. - Set
maxHeight={320}for long snippets — the block scrolls internally instead of pushing the page. - Override
themewith a Shiki{ light, dark }pair to match a brand palette.