CodeBlock
Displays syntax-highlighted source code with optional line numbers, toolbar, copy-to-clipboard button, and error diagnostics.
Supports both static code strings and custom rendering via Tokens
, LineNumbers
,
and Toolbar
subcomponents. For JavaScript and TypeScript, code can be type-checked,
formatted with Prettier (if available), and augmented with quick-info tooltips on hover.
In development, the component uses a Suspense fallback to render immediately while asynchronous syntax highlighting and analysis load in the background. In production, it renders the fully-resolved code block directly.
Style Overrides
The CodeBlock
component can be styled using the, css
, className
, and style
props to target specific descendant components. In most cases, its a good idea to create your own component that wraps the CodeBlock
component and applies the style overrides you need:
import {
type CodeBlockProps,
CodeBlock as DefaultCodeBlock,
Tokens,
} from 'renoun/components'
import styles from './CodeBlock.module.css'
export function CodeBlock(props: CodeBlockProps) {
return (
<DefaultCodeBlock
{...props}
css={{
// Clear the default styles
container: {
boxShadow: undefined,
borderRadius: undefined,
},
...props.css,
}}
className={{
container: styles.container,
token: styles.token,
...props.className,
}}
/>
)
}
Component Overrides
If you need more customization, the CodeBlock
component can be fully overridden by importing it from renoun/components
and extending it as needed:
import {
type CodeBlockProps,
CodeBlock as DefaultCodeBlock,
Tokens,
} from 'renoun/components'
export function CodeBlock({
children,
...props
}: Omit<CodeBlockProps, 'children'> & { children: string }) {
return (
<DefaultCodeBlock {...props}>
<pre
style={{
whiteSpace: 'pre',
wordWrap: 'break-word',
overflow: 'auto',
}}
>
<Tokens>{children}</Tokens>
</pre>
</DefaultCodeBlock>
)
}
Formatting
The CodeBlock
source text is formatted by default using prettier
if it is installed within the workspace. The shouldFormat
prop can be used to disable this behavior:
<CodeBlock language="ts" shouldFormat={false}>
const foo = 'bar'
</CodeBlock>
Examples
Basic
View Sourceconst beep = 'boop'
import { CodeBlock } from 'renoun' export function Basic() { return <CodeBlock language="ts">const beep = 'boop'</CodeBlock> }
Type Checking
View Sourceconst a = 1 a + b
import { CodeBlock } from 'renoun' export function TypeChecking() { return ( <CodeBlock language="ts" allowCopy={false} allowErrors showErrors> const a = 1; a + b; </CodeBlock> ) }
Ordered
View Sourceexample.tsconst a = 1
example.tsconst a = 1 const b = 2
import { CodeBlock } from 'renoun' export function Ordered() { return ( <div style={{ display: 'grid', gap: '2rem' }}> <CodeBlock path="01.example.ts">const a = 1;</CodeBlock> <CodeBlock path="02.example.ts">const a = 1; const b = 2;</CodeBlock> </div> ) }
Line Numbering
View Sourceline-numbers.ts1 2 3 4 5
const a = 1 const b = 2 const add = a + b const subtract = a - b
import { CodeBlock } from 'renoun' export function LineNumbering() { return ( <CodeBlock path="line-numbers.ts" showLineNumbers highlightedLines="4"> {`const a = 1;\nconst b = 2;\n\nconst add = a + b\nconst subtract = a - b`} </CodeBlock> ) }
Line Highlighting
View Sourceline-highlight.tsconst a = 1 const b = 2 const add = a + b const subtract = a - b
import { CodeBlock } from 'renoun' export function LineHighlighting() { return ( <CodeBlock path="line-highlight.ts" highlightedLines="2, 4"> {`const a = 1;\nconst b = 2;\n\nconst add = a + b\nconst subtract = a - b`} </CodeBlock> ) }
Line Focusing
View Sourceline-focus.tsconst a = 1 const b = 2 const add = a + b const subtract = a - b
import { CodeBlock } from 'renoun' export function LineFocusing() { return ( <CodeBlock path="line-focus.ts" focusedLines="2, 4"> {`const a = 1;\nconst b = 2;\n\nconst add = a + b\nconst subtract = a - b`} </CodeBlock> ) }
Line Highlight and Focus
View Sourceline-highlight-and-focus.tsconst a = 1 const b = 2 const add = a + b const subtract = a - b
import { CodeBlock } from 'renoun' export function LineHighlightAndFocus() { return ( <CodeBlock path="line-highlight-and-focus.ts" highlightedLines="2, 4" focusedLines="2, 4" > {`const a = 1;\nconst b = 2;\n\nconst add = a + b\nconst subtract = a - b`} </CodeBlock> ) }
Tokens Only
View Sourceconst a = 1 const b = 2 a + b
import { Tokens } from 'renoun' export function TokensOnly() { return ( <pre> <Tokens language="ts">{`const a = 1\nconst b = 2\na + b`}</Tokens> </pre> ) }
Custom Styles
View Source./counter/Counter.tsx1 2 3 4 5 6 7 8 9 10 11 12 13 14
'use client' import React from 'react' import { useCounter } from './useCounter.js' export default function Counter({ initialCount }: { initialCount: number }) { const { count, decrement, increment } = useCounter(initialCount) return ( <div> <button onClick={decrement}>-</button> <span>{count}</span> <button onClick={increment}>+</button> </div> ) }
import { CodeBlock, LineNumbers, Tokens, Toolbar } from 'renoun' import { dirname, join } from 'node:path' import { fileURLToPath } from 'node:url' import { readFile } from 'node:fs/promises' const directoryPath = dirname(fileURLToPath(import.meta.url)) export async function CustomStyles() { const code = await readFile( join(directoryPath, './counter/Counter.tsx'), 'utf-8' ) return ( <CodeBlock path="./counter/Counter.tsx" baseDirectory={directoryPath}> <div style={{ fontSize: '1rem', borderRadius: '0.25rem', boxShadow: '0 0 0 1px var(--color-separator)', }} > <Toolbar allowCopy css={{ padding: '0.5lh', boxShadow: 'inset 0 -1px 0 0 var(--color-separator)', }} /> <pre style={{ display: 'grid', gridTemplateColumns: 'min-content max-content', padding: '0.5lh 0', lineHeight: 1.4, whiteSpace: 'pre', wordWrap: 'break-word', overflow: 'auto', }} > <LineNumbers css={{ padding: '0 0.5lh', backgroundColor: 'var(--color-background)', }} /> <code style={{ paddingRight: '0.5lh' }}> <Tokens>{code}</Tokens> </code> </pre> </div> </CodeBlock> ) }