Overview
The Code Block component renders preformatted source code with optional syntax highlighting, line numbers, a copy-to-clipboard button, and language identification. It is essential for developer documentation, technical blogs, API references, design-system sites, and any interface where code needs to be displayed or shared.
Code blocks differ from inline code (<code> within running text) in that they are block-level elements representing complete code snippets — functions, configuration files, terminal commands, or multi-line examples. The <pre> element preserves whitespace and line breaks, while the nested <code> element carries the language semantics.
When to use a Code Block:
- To display source code examples in documentation
- For terminal/CLI commands or shell output
- To show configuration files (JSON, YAML, TOML)
- For API request/response payloads
- To present diff comparisons between code versions
When NOT to use a Code Block:
- For inline code references within a sentence — use
<code>inline - For user-generated content that happens to contain code — consider a sandboxed preview
- For poetry or preformatted non-code text — use
<pre>without syntax highlighting - For tabular data — use a Table
Typography is critical for code readability. Use the Font Explorer to evaluate monospace typefaces — Fira Code, JetBrains Mono, and Source Code Pro are popular choices with programming ligature support. Verify that your code block's foreground colors against its background pass contrast checks with the Contrast Checker, especially for syntax-highlighted tokens.
Variants
Common Code Block Variants
| Variant | Purpose | Visual Treatment |
|---|---|---|
| Standard | General code display with syntax highlighting | Dark or light background, monospace font, optional line numbers |
| Terminal | Shell commands and CLI output | Dark background, $ or > prompt prefix, green/white text on black |
| Diff | Before/after code comparison | Red (removed) and green (added) line highlights with -/+ prefixes |
| Inline Editor | Editable code for playground/sandbox contexts | Editable contenteditable or <textarea> with live syntax highlighting |
| Collapsed | Long code hidden behind an expand trigger | Shows first N lines with "Show more" button; prevents scroll fatigue |
| Multi-file | Tabbed interface showing multiple files | Tab bar with filenames, shared container, single active panel |
Theme Variants
| Theme | Background | Text Color | Use Case |
|---|---|---|---|
| Dark | #1e1e1e – #282c34 | #abb2bf – #d4d4d4 | Default for most dev docs. High contrast. |
| Light | #fafafa – #ffffff | #383a42 – #24292e | Matches light-mode UIs. GitHub-style. |
| High Contrast | #000000 | #ffffff with saturated tokens | Accessibility mode for low-vision users |
Feature Toggles
| Feature | Description |
|---|---|
| Line Numbers | Numbered gutter on the left. Disable for short snippets (< 5 lines). |
| Copy Button | One-click clipboard copy with confirmation feedback |
| Language Badge | Small label showing the language (e.g., "TypeScript", "bash") |
| Line Highlighting | Emphasize specific lines for teaching or code review |
| Word Wrap | Toggle between horizontal scroll and word wrapping |
Properties
Code Block Properties
| Property | Type | Default | Description |
|---|---|---|---|
language | string | 'text' | Programming language for syntax highlighting (e.g., 'typescript', 'python', 'bash') |
theme | 'dark' | 'light' | 'high-contrast' | 'dark' | Color theme for the code block |
showLineNumbers | boolean | true | Display line numbers in the gutter |
highlightLines | number[] | [] | Array of line numbers to visually emphasize |
showCopyButton | boolean | true | Show copy-to-clipboard button |
showLanguageBadge | boolean | true | Show language label in the header |
wordWrap | boolean | false | Wrap long lines instead of horizontal scrolling |
maxHeight | string | number | — | Maximum height before scrolling (e.g., '400px') |
fileName | string | — | File name to display in the header bar |
startLine | number | 1 | Starting line number for the gutter |
diff | boolean | false | Enable diff mode (lines prefixed with +/- are colored) |
children | string | — | The code content as a string |
Important: Always pass code content as a raw string, not as JSX children with embedded HTML. Syntax highlighters (Prism, Shiki, Highlight.js) expect plain text and will break on pre-parsed HTML entities.
Token Mappings
Design Token Mappings
| Token Category | Token Example | Code Block Usage |
|---|---|---|
| Color – Background | --color-code-bg (#1e1e1e) | Container background |
| Color – Text | --color-code-text (#d4d4d4) | Default unhighlighted text |
| Color – Gutter | --color-code-gutter (#858585) | Line number text color |
| Color – Highlight | --color-code-line-highlight (rgba(255,255,255,0.07)) | Highlighted line background |
| Color – Diff Add | --color-code-diff-add (rgba(40,167,69,0.15)) | Added line background in diff mode |
| Color – Diff Remove | --color-code-diff-remove (rgba(220,53,69,0.15)) | Removed line background in diff mode |
| Typography – Family | --font-family-mono | Monospace typeface. Choose with Font Explorer. |
| Typography – Size | --font-size-code (0.875rem) | Code text size — smaller than body to fit more content |
| Typography – Line Height | --line-height-code (1.6) | Line height for code readability |
| Spacing – Padding | --space-4 | Internal padding around code content |
| Border – Radius | --radius-md | Container corner rounding |
| Shadow | --shadow-sm | Optional subtle shadow for floating code blocks |
Syntax Highlighting Token Map
Most syntax highlighting libraries use these semantic categories:
| Token | Example Color (Dark) | Purpose |
|---|---|---|
keyword | #c678dd | const, function, if, return |
string | #98c379 | String literals |
number | #d19a66 | Numeric literals |
comment | #5c6370 | Comments — ⚠️ often fails contrast. Use Contrast Checker. |
function | #61afef | Function names and calls |
variable | #e06c75 | Variable names |
type | #e5c07b | Type annotations |
operator | #56b6c2 | Operators (=, +, =>) |
States
Code Block States
| State | Visual Treatment | Notes |
|---|---|---|
| Default | Rendered code with syntax highlighting | The standard resting state |
| Hover (Copy Button) | Copy button icon transitions from muted to full opacity | Button should be always visible, not appear on container hover — hidden buttons hurt discoverability |
| Copied | Copy icon changes to checkmark, tooltip shows "Copied!" | Auto-revert after 2 seconds |
| Loading | Skeleton shimmer matching code block dimensions | When code loads asynchronously or syntax highlighting is deferred |
| Error | Red border or banner indicating invalid/unparseable code | For live editors where code validation occurs |
| Collapsed | Shows first N lines with gradient fade-out and expand button | For long snippets. Button text: "Show all 142 lines" |
| Expanded | Full code visible with collapse button at bottom | "Show less" returns to collapsed state |
| Focused | Visible focus ring around container | When user tabs to the copy button or code region |
| Scrolling | Horizontal scrollbar visible for long lines | Fade gradient on right edge hints at overflowing content |
Copy Button Micro-interaction
The copy button interaction should follow this sequence:
- Idle: Clipboard icon, muted color
- Hover: Icon brightens, optional tooltip "Copy code"
- Click: Icon transitions to checkmark, text "Copied!" appears
- Confirmation hold: Checkmark visible for 2 seconds
- Reset: Smooth transition back to clipboard icon
Accessibility
Accessibility
Code blocks present unique accessibility challenges around keyboard navigation, screen reader behavior, and visual contrast for syntax tokens.
Semantic Structure (WCAG 1.3.1 – Info and Relationships):
- Use
<pre><code class="language-xxx">structure — the<pre>preserves whitespace, the<code>signals code content - Add
role="region"andaria-label="Code example in [language]"to the container for easy screen reader navigation - The language badge provides visual context — ensure it's also available programmatically via the
aria-label
Keyboard Access (WCAG 2.1.1 – Keyboard):
- The copy button must be keyboard-focusable (
<button>) and operable with Enter/Space - If the code block is horizontally scrollable, the container needs
tabindex="0"so keyboard users can scroll with arrow keys — addrole="region"andaria-labelwhen doing so - For tabbed multi-file code blocks, implement the Tabs keyboard pattern (Arrow keys between tabs, Tab to content)
Color Contrast (WCAG 1.4.3 – Contrast Minimum):
- Every syntax token color must achieve 4.5:1 contrast against the code block background. Use the Contrast Checker.
- Comments are the most common failure — the typically gray/muted comment color often falls below 4.5:1 on both dark and light backgrounds. Test this token explicitly.
- Line numbers (gutter) carry information and must meet 4.5:1 contrast
- Highlighted line backgrounds must not reduce token contrast below minimums
Non-Text Contrast (WCAG 1.4.11 – Non-Text Contrast):
- The copy button icon must have 3:1 contrast against its background
- Line highlighting background must be distinct enough (3:1 against default background) to be perceivable
Resize and Reflow (WCAG 1.4.10 – Reflow):
- Code blocks are exempt from reflow requirements (WCAG allows horizontal scrolling for preformatted content)
- However, provide a word-wrap toggle as a user preference for those who prefer it
- At 400% zoom, the code block container should remain usable — avoid fixed widths
Screen Reader Behavior:
- Screen readers read code blocks as continuous text. Syntax highlighting is purely visual and carries no semantic weight — this is acceptable
- Line numbers should not be selectable (use CSS
user-select: noneon the gutter) and should be hidden from screen readers (aria-hidden="true") to avoid "1 const 2 function 3 return" chaos - The copy button should announce "Copy code" and the confirmation "Code copied to clipboard" via
aria-live="polite"
Usage Guidelines
Usage Guidelines
Do:
- Specify the language accurately — wrong syntax highlighting is worse than none
- Include a copy button for any code users are expected to use
- Use line highlighting to draw attention to important lines in educational content
- Show file names when the code's location matters (e.g.,
src/App.tsx) - Keep code examples concise — show the minimum needed to illustrate the concept
- Provide both dark and light theme options if your site supports both modes
- Use a monospace font with programming ligatures for improved readability. Explore options with the Font Explorer.
Don't:
- Don't use syntax highlighting for plain text, logs, or terminal output — use
language="text"orlanguage="bash" - Don't auto-collapse short code blocks (under ~15 lines) — the expand/collapse adds unnecessary friction
- Don't disable text selection on code — users need to select and copy portions
- Don't apply word wrap by default — it breaks visual line structure that developers rely on for reading code
- Don't use code blocks for JSON/YAML configuration that users need to edit — provide a form interface with a "View as code" toggle
- Don't forget to escape HTML entities if rendering code server-side without a proper highlighter
Code Snippets
<!-- Standard code block with syntax highlighting (Prism.js) -->
<div class="code-block" role="region" aria-label="Code example in JavaScript">
<div class="code-block-header">
<span class="code-block-language">JavaScript</span>
<button class="code-block-copy" aria-label="Copy code">
<svg class="icon-clipboard" aria-hidden="true"><!-- clipboard icon --></svg>
</button>
</div>
<pre class="code-block-pre"><code class="language-javascript">function greet(name) {
return \`Hello, \${name}!\`;
}
console.log(greet('World'));</code></pre>
</div>
<!-- Terminal variant -->
<div class="code-block code-block--terminal" role="region" aria-label="Terminal command">
<div class="code-block-header">
<span class="code-block-dots" aria-hidden="true">
<span></span><span></span><span></span>
</span>
<span class="code-block-language">bash</span>
<button class="code-block-copy" aria-label="Copy command">
<svg class="icon-clipboard" aria-hidden="true"><!-- icon --></svg>
</button>
</div>
<pre class="code-block-pre"><code class="language-bash">npm install @stellae/components
npx stellae init</code></pre>
</div>
<!-- Diff variant -->
<div class="code-block code-block--diff" role="region" aria-label="Code diff">
<pre class="code-block-pre"><code class="language-diff">- const color = 'red';
+ const color = 'blue';
const size = 'medium';</code></pre>
</div>
<style>
.code-block {
border-radius: 8px;
overflow: hidden;
background: #1e1e1e;
font-family: 'Fira Code', 'Consolas', monospace;
font-size: 0.875rem;
line-height: 1.6;
}
.code-block-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 16px;
background: rgba(255, 255, 255, 0.05);
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.code-block-language {
font-size: 0.75rem;
color: #858585;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.code-block-copy {
background: none;
border: none;
color: #858585;
cursor: pointer;
padding: 4px;
border-radius: 4px;
transition: color 0.15s, background 0.15s;
}
.code-block-copy:hover {
color: #d4d4d4;
background: rgba(255, 255, 255, 0.1);
}
.code-block-pre {
margin: 0;
padding: 16px;
overflow-x: auto;
color: #d4d4d4;
}
.code-block--terminal {
background: #0d1117;
}
.code-block-dots span {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 50%;
margin-right: 6px;
}
.code-block-dots span:nth-child(1) { background: #ff5f56; }
.code-block-dots span:nth-child(2) { background: #ffbd2e; }
.code-block-dots span:nth-child(3) { background: #27c93f; }
</style>import React, { useState, useCallback } from 'react';
import styles from './CodeBlock.module.css';
import clsx from 'clsx';
interface CodeBlockProps {
language?: string;
theme?: 'dark' | 'light' | 'high-contrast';
showLineNumbers?: boolean;
highlightLines?: number[];
showCopyButton?: boolean;
showLanguageBadge?: boolean;
wordWrap?: boolean;
maxHeight?: string | number;
fileName?: string;
startLine?: number;
diff?: boolean;
children: string;
}
export function CodeBlock({
language = 'text',
theme = 'dark',
showLineNumbers = true,
highlightLines = [],
showCopyButton = true,
showLanguageBadge = true,
wordWrap = false,
maxHeight,
fileName,
startLine = 1,
diff = false,
children,
}: CodeBlockProps) {
const [copied, setCopied] = useState(false);
const lines = children.split('\n');
const handleCopy = useCallback(async () => {
try {
await navigator.clipboard.writeText(children);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
} catch {
/* fallback: textarea select + execCommand */
}
}, [children]);
return (
<div
className={clsx(styles.root, styles[theme], { [styles.diff]: diff })}
role="region"
aria-label={`Code example in ${language}`}
>
<div className={styles.header}>
{fileName && <span className={styles.fileName}>{fileName}</span>}
{showLanguageBadge && !fileName && (
<span className={styles.language}>{language}</span>
)}
{showCopyButton && (
<button
className={styles.copyButton}
onClick={handleCopy}
aria-label={copied ? 'Code copied to clipboard' : 'Copy code'}
>
{copied ? '✓ Copied' : 'Copy'}
</button>
)}
</div>
<pre
className={styles.pre}
style={{
maxHeight: maxHeight,
whiteSpace: wordWrap ? 'pre-wrap' : 'pre',
}}
>
<code className={`language-${language}`}>
{lines.map((line, i) => {
const lineNum = startLine + i;
const isHighlighted = highlightLines.includes(lineNum);
return (
<div
key={i}
className={clsx(styles.line, {
[styles.highlighted]: isHighlighted,
[styles.added]: diff && line.startsWith('+'),
[styles.removed]: diff && line.startsWith('-'),
})}
>
{showLineNumbers && (
<span className={styles.lineNumber} aria-hidden="true">
{lineNum}
</span>
)}
<span className={styles.lineContent}>{line}</span>
</div>
);
})}
</code>
</pre>
</div>
);
}Design Systems
Design System Implementations
Material Design (MUI) does not include a Code Block component in its core library. Teams typically use third-party libraries like react-syntax-highlighter (with Prism or Highlight.js backends) wrapped in MUI's <Paper> for consistent theming. MUI's documentation site itself uses a custom code block with Prism.js, copy buttons, and language tabs — but this component is not exported for external use.
Ant Design does not offer a Code Block component. Ant's documentation site uses a custom implementation with Prism.js. For projects using Ant Design, the recommendation is to integrate prism-react-renderer or react-syntax-highlighter and style them to match Ant's visual language using its token system.
Chakra UI includes no dedicated Code Block. The <Code> component handles inline code (colored background, monospace font). For block-level code, Chakra recommends composing <Box as="pre"> with a syntax highlighting library. The @chakra-ui/prose plugin styles native <pre><code> elements within prose content.
Bootstrap provides basic <pre> and <code> styling with scrollable overflow and monospace font. No syntax highlighting, copy button, or line numbers are included. Bootstrap's $code-color and $pre-color Sass variables control text color. For production code blocks, Bootstrap users add Prism.js or Highlight.js independently.
Apple Human Interface Guidelines addresses code display in the context of developer documentation (Xcode, Swift Playgrounds). Apple uses San Francisco Mono as its system monospace font with a proprietary syntax highlighting theme. In SwiftUI, there is no native code block view — developers use Text with attributed strings or integrate a WKWebView with a JavaScript-based highlighter.
Tailwind CSS styles <pre><code> blocks via the @tailwindcss/typography plugin: monospace font, rounded background, horizontal overflow scroll. Tailwind's utility classes enable quick custom code blocks: bg-gray-900 text-gray-100 rounded-lg p-4 font-mono text-sm overflow-x-auto. For syntax highlighting, the community pairs Tailwind with Shiki (build-time highlighting) or Prism.js. Use the Font Explorer to compare monospace typefaces like Fira Code, JetBrains Mono, and IBM Plex Mono.