Releases: vercel/streamdown
Release list
streamdown@2.6.0
Minor Changes
-
49bd143: fix(animate): serialize streaming animation across blocks
Word stagger now runs on a shared wall-clock timeline so sibling sections no longer fade in on top of each other during streaming. Related cleanup: trailing spaces stay inside animated spans (no early link underlines), animate wrappers drop when streaming ends, already-seen text stays steady under StrictMode, and un-animated streaming is no longer deferred behind a starvable transition.
-
b734cbf: - Add custom download filenames for code, table, and mermaid via the
controlsprop- Configure downloads with
download: { filename: "customName" }while keeping booleantrue/falseto show or hide - Preserve automatic file-extension mapping based on language or export format
- Remove the
codeDownloadprop in favor of the unifiedcontrolsAPI
- Configure downloads with
-
5faa6fa: Add
codeBlockMaxHeightandtableMaxHeightprops with streaming auto-scroll -
4436b56: - Add
controls.table.csvSeparator("," | ";" | "\t" | "auto") for table copy and download CSV- Reuse
tableDataToCSVseparator handling, including locale-aware"auto"mode - Improve CSV escaping to respect the selected separator for Excel compatibility
- Reuse
Patch Changes
-
6ec3c48: fix(animate): animate inline code during streaming
Skip the animate visitor on
pre(and svg/math/annotation) only — not barecode. Fenced/highlighted blocks stay un-split via theirpreancestor; inline backtick spans now get the same per-word fade-in as surrounding prose.Fixes #594
-
725e390: Forward rest props through block code. The
codecomponent spread its rest props on the inline branch and dropped them on the block branch, so an attribute a consumer put on a fenced code element never reached the DOM.CodeBlockBodynow takes part in that comparison, so a forwarded attribute updates instead of keeping the value it first rendered with. -
7e82400: Fix
dir="auto"in static mode to detect text direction per semantic block (instead of once for the whole document), keep code LTR, and use content-majority direction for mixed-script prose. -
fb5d7b9: Serialize Mermaid SVGs before download so HTML-style tags render as valid SVG markup.
-
fe38e75: Added accessibility improvements for code block controls by adding aria labels to copy/download buttons and announcing copy success state for screen readers.
-
b25dbdb: fix(custom-tags): render Markdown inside custom tags with multiline content
Adds a preprocessing step (
preprocessCustomTags) that normalizes multiline
custom tags into a blank-line-sandwiched HTML block so CommonMark interrupts
the raw-HTML block and parses the nested content as Markdown, with
parseMarkdownIntoBlocksre-merging the interrupted open/content/close tokens
so streaming still treats the whole custom tag as one block. Previously, when a
custom tag contained multiline content (e.g.<ai-thinking> **bold**</ai-thinking>), CommonMark treated the block as raw HTML, stripping
Markdown formatting. Tags listed inliteralTagContentare excluded from
re-parsing.Closes #478
-
26a8440: Fix doubled
user-content-prefix on footnote idsFootnote list items were rendered with
id="user-content-user-content-fn-1"because bothremark-rehypeandrehype-sanitizedefault theirclobberPrefixtouser-content-, so the prefix was applied twice. DisabledclobberPrefixonrehype-sanitizesoremark-rehyperemains the single, consistent prefixer of both footnote ids and backref hrefs — restoring working footnote navigation. -
f7d1fb5: fix(table): add
data-streamdown="table-wrapper"to fullscreen portal so copy/download dropdowns can find the table -
f0a726b: Add
aria-hidden="true"to decorative SVG icon components so screen readers rely on parent button labels instead of unlabeled icons. -
2ed2faa: Allow remend's
streamdown:incomplete-link sentinel through the default sanitize schema so streamed incomplete links render as pending instead of harden[blocked]. -
8fffa9d: Render the link safety modal through a portal to
document.bodyso it is no longer nested inside the paragraph's<p>element. This fixes the React hydration error "In HTML,<div>cannot be a descendant of<p>" that occurred when a link with link safety enabled appeared inside a paragraph. -
2733922: fix(mermaid): add aria-hidden to decorative SVG icons in mermaid toolbar buttons
Mermaid toolbar buttons (download, fullscreen, pan/zoom controls) already have
accessible titles/labels, but the inline SVG icons were exposed to the accessibility
tree causing "Content with images must be labeled" warnings. Added aria-hidden={true}
to all decorative icon elements in download-button, fullscreen-button, and pan-zoom
components.Fixes #485
-
8d36719: fix(deps): remove
mermaidas a hard runtime dependencyThis patch replaces the type import with a local structural type for
MermaidConfigso no type-level coupling to themermaidpackage remains in the distributed typings. Users who want fully-typed mermaid config can stillimport type { MermaidConfig } from 'mermaid'themselves; the structural type is compatible.Fixes #501
-
ea02609: Fix:
shikiThemeprop priority chain is now fully reachable.Previously,
shikiThemehad a default value in the props destructuring (= defaultShikiTheme), making theplugins?.code?.getThemes()fallback unreachable in both orderings. The fix removes the destructuring default and moves it to the end of the nullish coalescing chain, so all three levels are reachable:- Explicit
shikiThemeprop (highest priority) - Code plugin's
getThemes()(second priority) - Built-in
defaultShikiTheme(final fallback)
- Explicit
-
9813dd6: Fix type declarations requiring a
shikiinstall.BundledLanguage,BundledTheme, andThemeRegistrationAnyare now defined locally and re-exported fromstreamdown, so consumers can type-check without installingshiki. Runtime highlighting remains in@streamdown/code, which still depends onshiki. -
d893759: Fix mermaid fullscreen overlay accessibility and add stable selector
- Add
data-streamdown="mermaid-fullscreen"to fullscreen overlay for stable CSS targeting - Update fullscreen overlay semantics to match table fullscreen behavior
- Change
rolefrombuttontodialog - Add
aria-modal="true"for correct screen reader modal behavior - Improve accessibility consistency between mermaid and table fullscreen overlays
- Add
-
79c8575: fix issue with list markers, task-list checkboxes, images, and hr animations
-
a1a7142: feat: add image control options (
controls.image) to disable hover overlay and download button on imagesAdd
imageto thecontrolsprop, matching existingcode,table, andmermaidpatterns:controls={{ image: false }}hides the hover overlay and download buttoncontrols={{ image: { download: false } }}keeps the hover overlay but hides the download button
-
b250038: Fix accessibility warnings for Mermaid toolbar icon buttons:
- Add
aria-hidden="true"to all decorative SVG icons to hide them from screen readers - Add
aria-labelattributes to all icon-only buttons for proper screen reader announcements - Add translation keys (
zoomIn,zoomOut,resetView) for zoom controls
- Add
-
89c6877: Re-render memoized markdown components when their rendered output changes. The comparators compared source position, so a replacement of the same length — occupying the same lines and columns — was treated as unchanged and the component kept rendering the previous text.
-
e7bdf57: fix(mermaid): render the download and copy controls inside the Mermaid fullscreen portal so they're reachable when the diagram is expanded
-
8f02c09: Fix table copy and download actions not working in fullscreen mode.
- Support table lookup inside the fullscreen portal container.
- Restore copy and download functionality for fullscreen tables.
- Keep existing inline table controls behavior unchanged.
-
f46cd3c: - Fixed table copy losing line breaks inside cells containing
<br>elements.- Preserved multiline content during table data extraction.
- Improved copied Markdown, CSV, and TSV output consistency for multiline cells.
- Added coverage for
<br>handling in table extraction.
-
dc3f1d2: - Fix code block line wrapping when line numbers are disabled.
- Ensure code block lines are rendered as block elements regardless of the
lineNumberssetting. - Prevent multiple code lines from collapsing into a single visual line when
lineNumbers={false}.
- Ensure code block lines are rendered as block elements regardless of the
-
Updated dependencies [a99d675]
-
Updated dependencies [9f96409]
-
Updated dependencies [8093f2a]
-
Updated dependencies [57c3089]
- remend@1.3.1
remend@1.3.1
Patch Changes
-
a99d675: Fix crash on iOS 16.0-16.2 / Safari < 16.3 by removing the lookbehind assertion from the single-tilde escape pattern (#519).
JSCore on those versions doesn't support lookbehind (
(?<=...)) and throws aSyntaxErrorwhile the module is being evaluated, before any user code runs, so there is no way to catch it. The preceding word character is now captured and written back in the replacement instead. -
9f96409: Preserve complete italic emphasis when a closing asterisk is followed by word text.
-
8093f2a: Treat LaTeX paren and bracket math as protected math contexts during emphasis completion.
-
57c3089: Fix quadratic code-block scanning.
isInsideCodeBlocknow builds a linear-time position lookup (cached per text) instead of rescanning the whole prefix on every call, so handlers that probe many positions no longer degrade quadratically. Repairing an unclosed, bracket-heavy 58k-character code block drops from ~915ms to ~0.4ms per call.
streamdown@2.5.0
Minor Changes
- d6666b6: Add
lineNumbersprop to disable line numbers in code blocks - d4ec6c0: Add
metaprop toCustomRendererProps. Custom renderers now receive the raw metastring from the code fence (everything after the language identifier, e.g.```rust {1} title="foo"→meta = '{1} title="foo"'). The prop is optional (meta?: string) and isundefinedwhen no metastring is present. Existing custom renderers are unaffected.
Patch Changes
-
ac8d839: Add staggered
animation-delayto streaming word/character animations so new content cascades in sequentially instead of all animating simultaneously. Configurable via the newstaggeroption (default 40ms). Setstagger: 0to restore the previous behavior. -
add5374: Enable horizontal scrolling on code blocks so long lines are accessible instead of being clipped by
overflow-hidden. -
75845c0: Fix unnecessary re-renders of code blocks during streaming updates.
Problem: In streaming mode, when new content arrives (e.g. a paragraph is appended), completed code blocks that haven't changed were still re-rendering. This happened because the
Streamdowncomponent used inline object literals as default parameter values forlinkSafety({ enabled: true }). Every timechildrenchanged andStreamdownre-rendered, these inline defaults created new references, which caused thecontextValueuseMemo to recompute a newStreamdownContextobject. Since React propagates context changes throughmemoboundaries, any context consumer inside a memoizedBlock(such asCodeBlock) would re-render even though the block's own props were unchanged.Fix: Extract the inline default values for
linkSafetyinto module-level constants (defaultLinkSafetyConfig). This ensures referential stability across renders, socontextValueonly recomputes when the actual values change — not just becausechildrenupdated. -
8b1c262: fix: prepend UTF-8 BOM to CSV downloads for Excel compatibility
save()now prepends\uFEFFfortext/csvstring content so Excel on
Windows detects UTF-8 encoding instead of falling back to ANSI.TableDownloadButtonrefactored to usesave()instead of inline Blob
creation, ensuring the public API also gets the BOM fix.
-
b105c64: Fix custom tag content being prematurely split when content follows the opening tag on the same line and contains double newlines (
\n\n). The preprocessor now ensures proper HTML block structure so the parser treats the entire tag as a single unit. -
9e6f991: Increase dropdown z-index for table copy and download menus to prevent clipping by surrounding elements.
-
9c18748: docs: document required CSS custom properties (shadcn/ui design tokens) in README
-
7b62e9a: Replace Tailwind v4-only
*:last:and*:first:variant syntax with[&>*:last-child]:and[&>*:first-child]:arbitrary variants for compatibility with both Tailwind CSS v3 and v4. Fixes caret rendering on every line instead of only the last child in v3. -
Updated dependencies [e50b0c4]
-
Updated dependencies [716a5f0]
- remend@1.3.0
remend@1.3.0
Minor Changes
- e50b0c4: Add opt-in inline KaTeX completion (
$formula→$formula$) via a newinlineKatexoption that defaults tofalseto avoid ambiguity with currency symbols. Also fixes block KaTeX completion when streaming produces a partial closing$. - 716a5f0: Escape single
~between word characters to prevent false strikethrough rendering (e.g.20~25°Cno longer renders as strikethrough). Adds a newsingleTildeoption (enabled by default) that can be disabled via{ singleTilde: false }.
@streamdown/code@1.1.1
Patch Changes
- 651873d: Fall back to plain text highlighting when the code block language identifier is unknown or truncated mid-stream, preventing Shiki from throwing on unsupported language names.
@streamdown/cjk@1.0.3
Patch Changes
- 6f1ea07: Updated
remark-cjk-friendlyandremark-cjk-friendly-gfm-strikethroughfrom v1.x to v2.x. The only breaking change in v2.0.0 is dropping Node.js 16 support, which Streamdown has already dropped (requires Node.js ≥18), so there is no actual impact. The actual code is identical to the latest v1.x release (v2.0.1 only added the ability to import package.json).
streamdown@2.4.0
Minor Changes
-
5edff75: Clarified Tailwind
@sourceconfiguration for Streamdown and optional plugins.
Updated documentation to keep the global@sourcefor corestreamdownonly, move plugin@sourceguidance to plugin docs with examples, and add a caveat to include plugin entries only if installed. -
57cd3b5: Add support for custom starting line numbers in code blocks via the
startLinemeta option.Code blocks can now specify a starting line number in the meta string:
```js startLine=10 const x = 1; ```
This renders line numbers beginning at 10 instead of the default 1. The feature works by parsing the
startLine=Nvalue from the fenced-code meta string and applyingcounter-reset: line N-1to the<code>element. -
57cd3b5: Add support for customizing icons via the
iconsprop on<Streamdown>.Users can override any subset of the built-in icons (copy, download, zoom, etc.) by passing a
Partial<IconMap>:import { Streamdown, type IconMap } from "streamdown"; <Streamdown icons={{ CheckIcon: MyCheckIcon }}>{content}</Streamdown>;
Unspecified icons fall back to defaults.
-
01d27e9: Add support for custom Shiki themes via a
themesoption oncreateCodePlugin, accepting a[light, dark]pair of bundled theme names or full theme registration objects. -
2cf559d: Add a virtual
inlineCodekey to thecomponentsprop, allowing inline code spans to be styled independently from fenced code blocks without manually detecting block vs. inline context. -
27c7b03: Export table action components (
TableCopyDropdown,TableDownloadButton,TableDownloadDropdown) and utilities (extractTableDataFromElement,tableDataToCSV,tableDataToTSV,tableDataToMarkdown,escapeMarkdownTableCell,TableData), enabling custom table overrides to preserve copy/download interactivity. -
fb76275: Add a fullscreen overlay for tables with Escape/backdrop-click to close and scroll locking, controlled via
controls.table.fullscreen. Copy and download controls remain available in the fullscreen view. -
b392fbe: Add
literalTagContentprop that accepts an array of custom HTML tag names (e.g.['mention']) whose children should be treated as plain text, escaping markdown metacharacters so user-supplied labels aren't interpreted as formatting. -
c4c86fa: Add a
dirprop that accepts"ltr","rtl", or"auto". When set to"auto", each block's text direction is detected by scanning for the first strong Unicode character (Arabic, Hebrew, Thaana, etc.). -
00872f0: Add a
prefixprop that prepends a namespace to all generated Tailwind utility classes (e.g.flexbecomestw:flex), enabling Tailwind v4'sprefix()feature for projects that need to avoid class name collisions. -
401b901: Add support for custom renderers via
plugins.renderers, allowing fenced code blocks with specific languages to be rendered by a custom component instead of the defaultCodeBlock.
Patch Changes
-
f398611: Add
onAnimationStartandonAnimationEndcallback props that fire when streaming animation begins and completes, useful for coordinating UI state with the animation lifecycle. -
f2a7e51: Fix empty lines in syntax-highlighted code blocks collapsing into nothing by rendering a newline character for empty token rows, preserving whitespace when copying.
-
9ba8511: fix: prevent ordered list animation retrigger during streaming
When streaming content contains multiple ordered (or unordered) lists,
the Marked lexer merges them into a single block. As each new item appears
the block is re-processed through the rehype pipeline, re-creating all
data-sd-animatespans. This caused already-visible characters to re-run
their CSS entry animation.Two changes address the root cause:
-
Per-block
prevContentLengthtracking – eachBlockcomponent
now keeps auseRefwith the content length from its previous render.
Before each render theanimatePlugin.setPrevContentLength(n)method is
called so the rehype plugin can detect which text-node positions were
already rendered. Characters whose cumulative hast-text offset falls below
the previous raw-content length receive--sd-duration:0ms, making them
appear in their final state instantly rather than re-animating. -
Stable
animatePluginreference – theanimatePluginuseMemo
now uses value-based dependency comparison instead of reference equality
for theanimatedoption object. This prevents the plugin from being
recreated on every parent re-render when the user passes an inline object
literal (e.g.animated={{ animation: 'fadeIn' }}). A stable reference
is required because the rehype processor cache uses the function name as
its key and always returns the first cached closure; only the original
configobject is ever read by the processor.
-
-
781178b: Add a granular
controlsprop that accepts a boolean to toggle all controls or an object with per-feature flags (code,table,mermaid) for fine-grained control over copy, download, fullscreen, and pan/zoom buttons. -
e129f09: Add a
translationsprop for overriding all user-facing UI strings (copy/download button labels, modal text, image alt text, etc.), enabling full i18n support. -
Updated dependencies [a725579]
- remend@1.2.2
remend@1.2.2
Patch Changes
- a725579: Fix emphasis completion handlers incorrectly closing bold/italic/strikethrough markers that appear inside complete inline code spans (e.g.
`**bold`no longer gets a stray**appended outside the backticks).
@streamdown/code@1.1.0
Minor Changes
- 01d27e9: Add support for custom Shiki themes via a
themesoption oncreateCodePlugin, accepting a[light, dark]pair of bundled theme names or full theme registration objects.
streamdown@2.3.0
Minor Changes
-
3657e42: Add
useIsCodeFenceIncompletehook for detecting incomplete code fences during streamingCustom components can now detect when the code fence in their block is still being streamed. This is useful for deferring expensive renders (syntax highlighting, Mermaid diagrams) until the code block is complete.
import { useIsCodeFenceIncomplete } from "streamdown"; const MyCodeBlock = ({ children }) => { const isIncomplete = useIsCodeFenceIncomplete(); if (isIncomplete) { return <div>Loading code...</div>; } return ( <pre> <code>{children}</code> </pre> ); };
The hook returns
truewhen:- Streaming is active (
isAnimating={true}) - The component is in the last block being streamed
- That block has an unclosed code fence
The default code block component now uses this hook to set a
data-incompleteattribute when incomplete, enabling CSS-based loading states. - Streaming is active (
-
32fb079: fix: hide download button on broken images and display a custom "Image not available" message instead
-
d73d7bb: Make the action buttons in code block header sticky.
Ensures copy buttons remain accessible for long code blocks.
Improves usability when viewing large snippets. -
15645da: Move code block lazy loading to the highlighting layer so block shells render immediately with plain text content before syntax colors resolve. This improves visual stability and removes the spinner fallback for standard code blocks.
Patch Changes
- 0987479: fix: codeblock highlight flicker while streaming
- 5d438ca: Add support for copying table data as Markdown in TableCopyDropdown.
Introduces a Markdown copy option alongside existing formats.
Allows users to quickly copy tables in valid Markdown format. - ce9b4c2: Fix syntax highlighting
- ba03332: Redesign Mermaid diagram
- 6e91867: fix nested same-tag HTML block parsing in parseMarkdownIntoBlocks
- 7f9127b: Add
normalizeHtmlIndentationprop to prevent indented HTML tags from being treated as code blocks - fdef60d: Bump rehype-harden to fix "can't access property "type", node is undefined"
- 1abbf1e: Redesign table
- fb9f97c: handle custom tags with blank lines in content
- Updated dependencies [6374fbf]
- remend@1.2.1