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

  • const beep = 'boop'
    import { CodeBlock } from 'renoun/components'
    
    export function Basic() {
      return <CodeBlock language="ts">const beep = 'boop'</CodeBlock>
    }
  • Type Checking

    View Source
    const 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 Source
    const 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 Source
    1
    2
    3
    4
    5const 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 Source
    const 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 Source
    const 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 Source
    const 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 Source
    const 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.tsx
    1
    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>
      )
    }

API Reference