Code Blocks

Beautiful syntax highlighting and interactive code blocks powered by Shiki.

Streamdown provides beautiful, interactive code blocks with syntax highlighting powered by Shiki. Every code block includes a copy button and supports a wide range of programming languages.

Basic Usage

Create code blocks using triple backticks with an optional language identifier:

```javascript
function greet(name) {
  return `Hello, ${name}!`;
}
```

Streamdown will automatically apply syntax highlighting based on the specified language.

Enabling Syntax Highlighting

Syntax highlighting requires the code plugin. Install it:

npm install @streamdown/code

Then import and pass the plugin to Streamdown:

app/page.tsx
import { Streamdown } from "streamdown";
import { code } from "@streamdown/code";

export default function Page() {
  return (
    <Streamdown plugins={{ code: code }}>
      {markdown}
    </Streamdown>
  );
}

Without the code plugin, code blocks render as plain text with no highlighting.

Supported Languages

Streamdown supports 200+ programming languages through Shiki. All languages are lazy-loaded on demand, so only the grammars you use are downloaded.

Common Languages

  • Web: JavaScript, TypeScript, JSX, TSX, HTML, CSS
  • Data: JSON, YAML, TOML
  • Shell: Bash, Shell Script, PowerShell
  • Backend: Python, Go, Java, Rust, C, C++, C#, PHP, Ruby
  • Functional: Haskell, Elixir, Clojure, F#, OCaml
  • Markup: Markdown, LaTeX, MDX, XML
  • And 180+ more languages

Language Examples

TypeScript

```typescript
interface User {
  id: number;
  name: string;
  email: string;
}

async function fetchUser(id: number): Promise<User> {
  const response = await fetch(`/api/users/${id}`);
  return response.json();
}
```

Python

```python
def fibonacci(n: int) -> list[int]:
    """Generate Fibonacci sequence up to n terms."""
    fib = [0, 1]
    for i in range(2, n):
        fib.append(fib[i-1] + fib[i-2])
    return fib

print(fibonacci(10))
```

Rust

```rust
fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    let sum: i32 = numbers.iter().sum();
    println!("Sum: {}", sum);
}
```

Theme Configuration

Streamdown uses dual themes for light and dark modes. You can customize the themes using the shikiTheme prop:

app/page.tsx
import { Streamdown } from "streamdown";
import { code } from "@streamdown/code";

export default function Page() {
  return (
    <Streamdown
      plugins={{ code: code }}
      shikiTheme={["dracula", "dracula"]}
    >
      {markdown}
    </Streamdown>
  );
}

Available Themes

Streamdown supports all Shiki themes including:

  • github-light (default light theme)
  • github-dark (default dark theme)
  • dracula, nord, one-dark-pro, monokai
  • catppuccin-latte, catppuccin-mocha
  • vitesse-light, vitesse-dark
  • tokyo-night, slack-dark, slack-ochin
  • And many more

Interactive Features

Copy Button

Every code block includes a copy button that appears on hover. Users can click to copy the entire code block content to their clipboard.

The copy button:

  • Appears on hover (desktop) or is always visible (mobile)
  • Provides visual feedback on successful copy
  • Is automatically disabled during streaming (when isAnimating={true})

Disable Copy Button

You can disable the copy button using the controls prop:

app/page.tsx
<Streamdown controls={{ code: false }}>{markdown}</Streamdown>

Or disable all controls:

app/page.tsx
<Streamdown controls={false}>{markdown}</Streamdown>

Inline Code

Inline code uses backticks and receives subtle styling:

Use the `useState` hook to manage state in React.

Inline code is styled with:

  • Monospace font family
  • Subtle background color
  • Rounded corners
  • Appropriate padding

Code Block Styling

Code blocks include:

  • Line Numbers - Optional line numbers for reference
  • Rounded Corners - Modern, polished appearance
  • Proper Padding - Comfortable spacing
  • Scrolling - Horizontal scroll for long lines
  • Responsive Design - Adapts to container width

Streaming Considerations

Code blocks work seamlessly with streaming content:

Incomplete Code Blocks

When a code block is streaming in, Streamdown handles the incomplete state gracefully:

```javascript
function example() {
  // Streaming in progress...
```

The unterminated block parser ensures the code block renders properly even without the closing backticks.

Disabling Interactions During Streaming

Use the isAnimating prop to disable copy buttons while streaming:

app/page.tsx
<Streamdown isAnimating={isStreaming}>{markdown}</Streamdown>

This prevents users from copying incomplete code.

Plugin Interface

The Code plugin implements the CodeHighlighterPlugin interface:

interface CodeHighlighterPlugin {
  name: "shiki";
  type: "code-highlighter";
  highlight: (options: HighlightOptions, callback?: (result: HighlightResult) => void) => HighlightResult | null;
  supportsLanguage: (language: BundledLanguage) => boolean;
  getSupportedLanguages: () => BundledLanguage[];
  getThemes: () => [BundledTheme, BundledTheme];
}

Exported Types

import type {
  CodeHighlighterPlugin,
  HighlightOptions,
  HighlightResult,
} from '@streamdown/code';

// HighlightOptions - parameters for highlighting
interface HighlightOptions {
  code: string;
  language: BundledLanguage;
  themes: [string, string];
}

// HighlightResult - Shiki's TokensResult type
type HighlightResult = TokensResult;

Programmatic Highlighting

Use the plugin directly for custom highlighting:

import { code } from '@streamdown/code';

// Check language support
if (code.supportsLanguage('typescript')) {
  code.highlight(
    { code: 'const x = 1;', language: 'typescript', themes: ['github-light', 'github-dark'] },
    (result) => {
      // Handle highlighted tokens
      console.log(result.tokens);
    }
  );
}