LumisDocs
Integrations

React

Use Lumis in React with client `CodeBlock` and `InlineCode` components, a `useLumis` hook, and server renderers.

Examples:

@lumis-sh/react follows the same formatter-first API as the rest of Lumis, but splits client and server helpers.

Install

npm install @lumis-sh/react @lumis-sh/lumis \
  @lumis-sh/themes react \
  @lumis-sh/wasm-bundle-web

Client component

Use CodeBlock when you want a drop-in React component.

Simple

import {CodeBlock} from '@lumis-sh/react'
import {htmlInline} from '@lumis-sh/lumis/formatters'
import latte from '@lumis-sh/themes/catppuccin_latte'
import web from '@lumis-sh/wasm-bundle-web'

const codeString = `export function Hello() {
  return <h1>Hello</h1>
}`

export function Example() {
  return (
    <CodeBlock
      formatter={htmlInline({
        language: web.tsx,
        theme: latte,
      })}
    >
      {codeString}
    </CodeBlock>
  )
}

Reuse one highlighter

import {CodeBlock} from '@lumis-sh/react'
import {createHighlighter} from '@lumis-sh/lumis'
import web from '@lumis-sh/wasm-bundle-web'
import {htmlInline} from '@lumis-sh/lumis/formatters'
import latte from '@lumis-sh/themes/catppuccin_latte'

const highlighter = createHighlighter({
  languages: [web],
})

const codeString = `export function Hello() {
  return <h1>Hello</h1>
}`

export function Example() {
  return (
    <CodeBlock
      highlighter={highlighter}
      formatter={htmlInline({
        language: web.tsx,
        theme: latte,
      })}
    >
      {codeString}
    </CodeBlock>
  )
}

If you do not pass highlighter, CodeBlock uses a shared internal highlighter. Passing your own highlighter is the better choice when you want to register bundles or reuse one instance across many blocks.

Inline code

Use InlineCode for code inside a sentence. It takes the same formatter as CodeBlock and renders a <code> holding the highlighted tokens, with the lumis class and the theme's colors, instead of a <pre> block.

import {InlineCode} from '@lumis-sh/react'
import {htmlInline} from '@lumis-sh/lumis/formatters'
import latte from '@lumis-sh/themes/catppuccin_latte'
import web from '@lumis-sh/wasm-bundle-web'

const formatter = htmlInline({language: web.javascript, theme: latte})

export function Example() {
  return (
    <p>
      Call <InlineCode formatter={formatter}>{'createHighlighter()'}</InlineCode> once.
    </p>
  )
}

Pass attrs to add attributes to the <code>. class and style merge with the ones Lumis sets:

<InlineCode formatter={formatter} attrs={{class: 'api', id: 'setup'}}>
  {'createHighlighter()'}
</InlineCode>

InlineCode works with htmlInline, htmlLinked and htmlMultiThemes. Other formatters have no inline form and raise an error. With htmlLinked, the theme stylesheet colors the <code> through its lumis class.

Hook

Use useLumis() when you want to control the loading UI yourself.

import {useLumis} from '@lumis-sh/react'
import {createHighlighter} from '@lumis-sh/lumis'
import web from '@lumis-sh/wasm-bundle-web'
import {htmlInline} from '@lumis-sh/lumis/formatters'
import latte from '@lumis-sh/themes/catppuccin_latte'

const highlighter = createHighlighter({
  languages: [web],
})

export function Example() {
  const {content, error, isLoading} = useLumis({
    children: 'export const answer = 42',
    formatter: htmlInline({
      language: 'typescript',
      theme: latte,
    }),
    highlighter,
  })

  if (isLoading) return <p>Loading syntax highlighter...</p>
  if (error) return <p>{error.message}</p>
  return <>{content}</>
}

Pass inline: true, and optionally attrs, to get the InlineCode output instead of a block.

error is an Error when highlighting or language loading fails, and undefined otherwise.

Server rendering

Use renderCodeBlock() from the server subpath when you need highlighted output on the server.

This is a good fit for React Server Components and Next.js App Router pages.

import {renderCodeBlock} from '@lumis-sh/react/server'
import web from '@lumis-sh/wasm-bundle-web'
import {htmlInline} from '@lumis-sh/lumis/formatters'
import latte from '@lumis-sh/themes/catppuccin_latte'

const codeString = `export function Hello() {
  return <h1>Hello</h1>
}`

export async function Article() {
  const block = await renderCodeBlock({
    children: codeString,
    formatter: htmlInline({
      language: web.tsx,
      theme: latte,
    }),
  })

  return <article>{block}</article>
}

renderInlineCode() is its counterpart for inline code, and takes the same options plus attrs:

import {renderInlineCode} from '@lumis-sh/react/server'
import web from '@lumis-sh/wasm-bundle-web'
import {htmlInline} from '@lumis-sh/lumis/formatters'
import latte from '@lumis-sh/themes/catppuccin_latte'

export async function Setup() {
  const code = await renderInlineCode({
    children: 'createHighlighter()',
    formatter: htmlInline({language: web.javascript, theme: latte}),
  })

  return <p>Call {code} once.</p>
}

Reusing one highlighter

Create one Highlighter and pass it into CodeBlock or useLumis():

import {createHighlighter} from '@lumis-sh/lumis'
import web from '@lumis-sh/wasm-bundle-web'
import {CodeBlock} from '@lumis-sh/react'
import {htmlInline} from '@lumis-sh/lumis/formatters'
import latte from '@lumis-sh/themes/catppuccin_latte'

const codeString = `export const answer = 42`

const highlighter = await createHighlighter({
  languages: [web],
})

export function Example() {
  return (
    <CodeBlock
      highlighter={highlighter}
      formatter={htmlInline({
        language: 'tsx',
        theme: latte,
      })}
    >
      {codeString}
    </CodeBlock>
  )
}

This is the best option when you want to register a bundle and render many code blocks on one page.

Behavior

  • formatter is the single source of truth for the language
  • CodeBlock, InlineCode and useLumis() are client exports from @lumis-sh/react
  • renderCodeBlock() and renderInlineCode() are server exports from @lumis-sh/react/server
  • the React helpers call highlighter.loadLanguage(formatter.language) before highlighting
  • when the language is already loaded, Lumis reuses the cached result
  • for true server-rendered highlighting, prefer renderCodeBlock()
  • CodeBlock, InlineCode and useLumis() re-highlight when children, formatter, or highlighter changes, and InlineCode and useLumis({inline: true}) also when attrs changes

On this page