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/codeThen import and pass the plugin to Streamdown:
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:
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,monokaicatppuccin-latte,catppuccin-mochavitesse-light,vitesse-darktokyo-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:
<Streamdown controls={{ code: false }}>{markdown}</Streamdown>Or disable all controls:
<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.
Loading Behavior
Code block shells render immediately with plain text content, then syntax colors are applied when highlighting resolves.
This keeps code readable on first paint and improves visual stability during lazy highlight loading.
Disabling Interactions During Streaming
Use the isAnimating prop to disable copy buttons while streaming:
<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);
}
);
}