--- name: streamdown description: | Expert guidance for Vercel's Streamdown library - a streaming-optimized react-markdown replacement for AI applications. Use when: (1) Rendering AI-generated markdown from useChat/streamText, (2) Building chat UIs with streaming responses, (3) Migrating from react-markdown to streaming-friendly rendering, (4) Configuring code blocks (Shiki), math (KaTeX), diagrams (Mermaid), (5) Handling incomplete markdown during AI streaming (remend preprocessor), (6) Customizing markdown styling with Tailwind/CSS variables, (7) Securing AI output with rehype-harden (link/image protocols). Triggers: Streamdown, streaming markdown, AI chat markdown, react-markdown replacement, AI Elements Response, incomplete markdown, remend, Shiki themes, Mermaid diagrams, KaTeX math, rehype-harden, isAnimating, markdown streaming. --- # Streamdown - AI Streaming Markdown Streamdown is a drop-in react-markdown replacement designed for AI-powered streaming applications. It handles incomplete markdown syntax gracefully using the remend preprocessor. ## Quick Start ### Installation ```bash # Direct installation pnpm add streamdown # Or via AI Elements CLI (includes Response component) pnpm dlx ai-elements@latest add message ``` ### Tailwind Configuration **Tailwind v4** (globals.css): ```css @source "../node_modules/streamdown/dist/*.js"; ``` **Tailwind v3** (tailwind.config.js): ```js module.exports = { content: [ './app/**/*.{js,ts,jsx,tsx}', './node_modules/streamdown/dist/*.js', ], } ``` ### Basic Chat Example ```tsx 'use client'; import { useChat } from '@ai-sdk/react'; import { Streamdown } from 'streamdown'; export default function Chat() { const { messages, sendMessage, status } = useChat(); return ( <> {messages.map(message => (
{message.parts .filter(part => part.type === 'text') .map((part, index) => ( {part.text} ))}
))} ); } ``` ## Core Props | Prop | Type | Default | Description | |------|------|---------|-------------| | `children` | `string` | required | Markdown content to render | | `isAnimating` | `boolean` | `false` | Disables interactive controls during streaming | | `mode` | `"streaming" \| "static"` | `"streaming"` | Rendering mode | | `shikiTheme` | `[BundledTheme, BundledTheme]` | `['github-light', 'github-dark']` | Light/dark syntax themes | | `controls` | `ControlsConfig \| boolean` | `true` | Button visibility for code/table/mermaid | | `mermaid` | `MermaidOptions` | `{}` | Diagram configuration | | `components` | `object` | `{}` | Custom element overrides | | `className` | `string` | `""` | Container CSS class | | `remarkPlugins` | `Pluggable[]` | GFM, math, CJK | Markdown preprocessing | | `rehypePlugins` | `Pluggable[]` | raw, katex, harden | HTML processing | | `parseIncompleteMarkdown` | `boolean` | `true` | Enable remend preprocessor | ## AI SDK Integration ### Status-Based isAnimating The `status` from useChat maps directly to Streamdown's `isAnimating`: ```tsx const { messages, status } = useChat(); // status: 'submitted' | 'streaming' | 'ready' | 'error' {content} ``` ### Message Parts Pattern AI SDK v6 uses message parts instead of content string: ```tsx {messages.map(message => (
{message.parts .filter(part => part.type === 'text') .map((part, index) => ( {part.text} ))}
))} ``` ### Memoized Response Component Wrap Streamdown with React.memo for performance: ```tsx import { memo, ComponentProps } from 'react'; import { Streamdown } from 'streamdown'; export const Response = memo( ({ className, ...props }: ComponentProps) => ( ) ); ``` ## Configuration Examples ### Shiki Themes ```tsx import type { BundledTheme } from 'shiki'; const themes: [BundledTheme, BundledTheme] = ['github-light', 'github-dark']; {content} ``` ### Controls ```tsx {content} ``` ### Mermaid Diagrams ```tsx import type { MermaidConfig } from 'streamdown'; const mermaidConfig: MermaidConfig = { theme: 'base', themeVariables: { fontFamily: 'Inter, sans-serif', primaryColor: 'hsl(var(--primary))', lineColor: 'hsl(var(--border))', }, }; {content} ``` ### Custom Error Component for Mermaid ```tsx import type { MermaidErrorComponentProps } from 'streamdown'; const MermaidError = ({ error, chart, retry }: MermaidErrorComponentProps) => (

Failed to render diagram

); {content} ``` ### Custom Components Override any markdown element: ```tsx

{children}

, a: ({ href, children }) => ( {children} ), code: ({ children, className }) => ( {children} ), }} > {content}
``` ### Security Configuration Restrict protocols for AI-generated content: ```tsx import { defaultRehypePlugins } from 'streamdown'; import { harden } from 'rehype-harden'; {content} ``` ## Streaming vs Static Mode | Mode | Use Case | Features | |------|----------|----------| | `streaming` | AI chat responses | Block parsing, incomplete markdown handling, memoization | | `static` | Blog posts, docs | Simpler rendering, no streaming optimizations | ```tsx // Static mode for pre-rendered content {blogContent} ``` ## Built-in Features - **GFM**: Tables, task lists, strikethrough, autolinks - **Math**: KaTeX rendering with `$$...$$` syntax - **Code**: Shiki syntax highlighting (200+ languages) - **Diagrams**: Mermaid with interactive controls - **CJK**: Proper emphasis handling for Chinese/Japanese/Korean - **Security**: rehype-harden for link/image protocol restrictions ## Reference Files | Reference | Topics | |-----------|--------| | [api-reference.md](references/api-reference.md) | Complete props, types, plugins, data attributes | | [ai-sdk-integration.md](references/ai-sdk-integration.md) | useChat patterns, server setup, message parts | | [styling-security.md](references/styling-security.md) | Tailwind, CSS variables, custom components, rehype-harden | ## Common Patterns ### Next.js Configuration If you see bundling errors with Mermaid: ```js // next.config.js module.exports = { serverComponentsExternalPackages: ['langium', '@mermaid-js/parser'], webpack: (config, { isServer }) => { if (!isServer) { config.resolve.alias = { ...config.resolve.alias, 'vscode-jsonrpc': false, 'langium': false, }; } return config; }, }; ``` ### Shiki External Package ```js // next.config.js { transpilePackages: ['shiki'], } ``` ## Version Notes - **Streamdown**: Works with React 18+ (optimized for React 19) - **AI SDK**: Designed for v6 (status-based streaming state) - **Tailwind**: Supports v3 and v4 configurations