---
title: useHighlightedCode
description: Highlights code with Shiki, one React node per line, for a Code Block.
icon: code
author:
  name: shadcn
  url: https://github.com/shadcn
search:
  keywords: [syntax highlighting, shiki, streaming]
related:
  - /code-block
  - /use-shiki
---

<PoweredBy packages={[
  { name: 'Shadcn UI', url: 'https://ui.shadcn.com/docs/components/base/code-block' },
  { name: 'Shiki', url: 'https://shiki.style/' },
]} />

### Installation

```package-install
npx shadcn@latest add @redpanda/use-highlighted-code
```

The install brings the `highlighter` library with it. [Code Block](/docs/code-block) installs both.

`useHighlightedCode(code, language)` returns one React node per line. Each one goes in a `CodeBlockLine`. [`CodeBlockLines`](/docs/code-block#syntax-highlighting) calls it for you and keys the lines, so reach for the hook when you render the lines yourself. Every token carries both themes' colours, and the theme's `code-token` utility picks the one for the theme around it, so update `@redpanda/theme` along with the hook.

## Usage

```tsx lineNumbers
"use client"

import {
  CodeBlock,
  CodeBlockContent,
  CodeBlockLine,
} from "@/components/redpanda-ui/components/code-block"
import { useHighlightedCode } from "@/components/redpanda-ui/lib/use-highlighted-code"

export function Snippet({ code }: { code: string }) {
  const lines = useHighlightedCode(code, "yaml")

  return (
    <CodeBlock>
      <CodeBlockContent lineNumbers>
        {lines.map((line, index) => (
          <CodeBlockLine key={index}>{line}</CodeBlockLine>
        ))}
      </CodeBlockContent>
    </CodeBlock>
  )
}
```

## Behavior

- **Plain lines come first.** The hook returns the code split into lines until the language loads, so the block keeps its size when the colours arrive.
- **Each language loads on first use**, as its own chunk. An unlisted language stays plain, and loads nothing.
- **A trailing newline is ignored**, so it does not render as an empty last line.
- **Streaming only tokenizes new lines.** When the code grows, the finished lines keep their nodes, and only the lines after them are tokenized, from the grammar state the last finished line left.
- **`"ansi"` renders terminal colours** from ANSI escape codes, one line at a time.

## Languages

The list lives in `lib/highlighter`: `bash`, `css`, `diff`, `go`, `html`, `java`, `javascript`, `json`, `jsx`, `log`, `markdown`, `powershell`, `protobuf`, `python`, `rust`, `sql`, `toml`, `tsx`, `typescript`, and `yaml`. Aliases include `ts`, `js`, `sh`, `shell`, `zsh`, `yml`, `md`, `py`, `rs`, `proto`, `ps1`, and `golang`, and a `language-*` class from a Markdown fence resolves too. Add a language with one line:

```tsx
const languages = {
  // ...
  kotlin: () => import("shiki/langs/kotlin.mjs"),
}
```

## On the server

`highlightCode(code, language)` from `lib/highlighter` is async, so a Server Component can highlight and keep Shiki out of the client bundle. It returns the same lines, or `null` for an unlisted language.

```tsx
import { highlightCode } from "@/components/redpanda-ui/lib/highlighter"

const lines = (await highlightCode(code, "sql")) ?? code.split("\n")
```

## API

| Prop | Type | Default | Description |
| - | - | - | - |
| `code` | `string` | - | The code to highlight. It may grow between renders as it streams. |
| `language` | `string` | - | A listed language or alias, a `language-*` class, or `"ansi"`. Anything else stays plain. |

Returns `React.ReactNode[]`, one node per line.

## Credits

- Based on the `useHighlightedCode` hook from the [Shadcn UI Code Block](https://ui.shadcn.com/docs/components/base/code-block).
