# React (/integrations/react)

Examples:

- [Vite React example](https://github.com/leandrocp/lumis/tree/main/packages/javascript/react/examples/react)
- [Next.js App Router example](https://github.com/leandrocp/lumis/tree/main/packages/javascript/react/examples/next-app-router)

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

## Install

```bash
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

```tsx
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

```tsx
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.

## Hook

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

```tsx
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}</>
}
```

`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.

```tsx
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>
}
```

## Reusing one highlighter

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

```tsx
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` and `useLumis()` are client exports from `@lumis-sh/react`
- `renderCodeBlock()` is a server export 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` and `useLumis()` re-highlight when `children`, `formatter`, or `highlighter` changes