Skip to main content

CodeBlock

A lightweight syntax-highlighted code block with copy-to-clipboard, line numbers, and automatic dark mode support. Zero external dependencies for syntax highlighting.

import { CodeBlock } from "@ninna-ui/code-block"
pnpm add @ninna-ui/code-block

Requires @ninna-ui/core (auto-installed) + CSS setup.

View source

Usage

Import and use the CodeBlock component to display syntax-highlighted code.

1. Install

pnpm add @ninna-ui/code-block

2. Add CSS import

/* your CSS entry point (e.g. src/index.css) */
@import "tailwindcss";
@import "@ninna-ui/core/theme/presets/default.css";
/* Code block syntax token colors */
@import "@ninna-ui/code-block/styles";

The @import "@ninna-ui/code-block/styles" line loads the syntax token CSS custom properties. Without it the code block renders but syntax colors will be missing.

3. Use

import { CodeBlock } from "@ninna-ui/code-block";
const code = `import { Button } from "@ninna-ui/primitives";
export default function App() {
return <Button color="primary">Click me</Button>;
}`;
export default function Example() {
return <CodeBlock code={code} />;
}

Basic

A simple code block with TSX syntax highlighting and copy button.

import { Button } from "@ninna-ui/primitives";
export default function App() {
return <Button color="primary">Click me</Button>;
}

Line Numbers

Enable line numbers for longer code snippets.

1import { useState } from "react";
2import { Button, Heading, Text } from "@ninna-ui/primitives";
3import { Alert } from "@ninna-ui/feedback";
4import { VStack } from "@ninna-ui/layout";
5
6export default function App() {
7 const [count, setCount] = useState(0);
8
9 return (
10 <VStack gap={4} className="p-8">
11 <Heading as="h1" size="3xl">Counter: {count}</Heading>
12 <Text className="text-base-content/70">Click to increment.</Text>
13 <Button color="primary" onClick={() => setCount(c => c + 1)}>
14 Increment
15 </Button>
16 {count > 5 && (
17 <Alert color="success" variant="soft">
18 You clicked more than 5 times!
19 </Alert>
20 )}
21 </VStack>
22 );
23}

Without Copy Button

Hide the copy button for read-only display.

pnpm add @ninna-ui/primitives @ninna-ui/code-block

CSS / Multi-language

The highlighter handles CSS, HTML, and mixed content alongside TSX.

1/* Custom theme with oklch colors */
2:root,
3[data-theme="my-brand"] {
4 color-scheme: light;
5
6 --color-primary: oklch(0.55 0.20 250);
7 --color-primary-content: oklch(0.97 0.01 250);
8
9 --color-base-100: oklch(1.0 0 0);
10 --color-base-content: oklch(0.21 0.021 260);
11}

Always Visible Copy

Keep the copy button visible at all times instead of only on hover.

pnpm add @ninna-ui/primitives @ninna-ui/code-block

Plain Text (No Highlight)

Use language="bash" or language="text" to disable syntax highlighting.

1$ pnpm add @ninna-ui/primitives
2$ pnpm dev
3 ➜ Local: http://localhost:5173/
4 ➜ press h + enter to show help

Color Scheme

Force light or dark syntax colors regardless of the current page theme. Useful when embedding a CodeBlock inside a section that has a different background.

colorScheme="light" (always light)

import { useState } from "react";
import { Button } from "@ninna-ui/primitives";
export default function Counter() {
const [count, setCount] = useState(0);
return (
<Button onClick={() => setCount(c => c + 1)}>
Count: {count}
</Button>
);
}

colorScheme="dark" (always dark)

import { useState } from "react";
import { Button } from "@ninna-ui/primitives";
export default function Counter() {
const [count, setCount] = useState(0);
return (
<Button onClick={() => setCount(c => c + 1)}>
Count: {count}
</Button>
);
}

colorScheme="auto" (follows page theme)

import { useState } from "react";
import { Button } from "@ninna-ui/primitives";
export default function Counter() {
const [count, setCount] = useState(0);
return (
<Button onClick={() => setCount(c => c + 1)}>
Count: {count}
</Button>
);
}

Custom Styles

Customize the appearance with className.

const greeting = "Hello, world!";
console.log(greeting);
const greeting = "Hello, world!";
console.log(greeting);

API Reference

Complete list of props for the CodeBlock component.

Props

PropTypeDefaultDescription
code*string-The code string to display with syntax highlighting
language'tsx' | 'jsx' | 'typescript' | 'javascript' | 'css' | 'html' | 'json' | 'bash' | 'text''tsx'Language for syntax highlighting. Use 'text' or 'bash' for no highlighting.
colorScheme'light' | 'dark' | 'auto''auto'Force a specific syntax color scheme. 'auto' follows the page theme, 'light' always uses light colors, 'dark' always uses dark colors.
showLineNumbersbooleanfalseShow line numbers in the gutter
showCopyButtonbooleantrueShow a copy-to-clipboard button (visible on hover by default)
copyButtonAlwaysVisiblebooleanfalseAlways show the copy button instead of only on hover
classNamestring-Additional CSS classes for the root container
aria-labelstring-Accessible label for the code block container

Accessibility

  • Uses semantic pre and code elements for proper screen reader announcement
  • Supports aria-label and other ARIA attributes via props spread
  • Copy button has descriptive aria-label that updates on copy ("Copy code to clipboard" / "Code copied")
  • Decorative SVG icons use aria-hidden="true"
  • Syntax colors meet WCAG AA contrast requirements against both light and dark backgrounds
  • Line numbers use select-none to prevent accidental copying