CodeBlock
Renders a code block with tokenized source code, line numbers, and a toolbar.
When targeting JavaScript or TypeScript languages, the provided source code is
type-checked and will throw errors that can be optionally displayed. Additionally,
the source code will be formatted using prettier
if installed and quick info
is available when hovering symbols.
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/components' export function Basic() { return <CodeBlock language="ts">const beep = 'boop'</CodeBlock> }
Type Checking
View Sourceconst a = 1; a + b;
import { CodeBlock } from 'renoun/components' export function TypeChecking() { return ( <CodeBlock language="ts" allowCopy={false} allowErrors showErrors> const a = 1; a + b; </CodeBlock> ) }
Ordered
View Sourceconst a = 1;
const a = 1; const b = 2;
import { CodeBlock } from 'renoun/components' 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 Source1 2 3 4 5
const a = 1; const b = 2; const add = a + b const subtract = a - b
import { CodeBlock } from 'renoun/components' 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 Sourceconst a = 1; const b = 2; const add = a + b const subtract = a - b
import { CodeBlock } from 'renoun/components' 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 Sourceconst a = 1; const b = 2; const add = a + b const subtract = a - b
import { CodeBlock } from 'renoun/components' 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 Sourceconst a = 1; const b = 2; const add = a + b const subtract = a - b
import { CodeBlock } from 'renoun/components' 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/components' 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/components' 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> ) }