Skip to content

fix(streamdown): render code blocks incrementally during streaming#474

Open
mvanhorn wants to merge 1 commit intovercel:mainfrom
mvanhorn:osc/473-fix-code-block-streaming
Open

fix(streamdown): render code blocks incrementally during streaming#474
mvanhorn wants to merge 1 commit intovercel:mainfrom
mvanhorn:osc/473-fix-code-block-streaming

Conversation

@mvanhorn
Copy link

Summary

  • Fixes the animate plugin to include code/pre elements in its animation pass when the code fence is still open (incomplete)
  • Adds setAnimateCodeBlocks method to AnimatePlugin interface so the Block component can toggle code animation per-block
  • Once the code fence closes, animation reverts to default behavior (skip code blocks for syntax highlighting compatibility)

Problem

When using <Streamdown animated isAnimating>, prose text streams with word-by-word fade-in animation. But the animate plugin unconditionally skipped all code and pre elements (via SKIP_TAGS), so code block content appeared instantly without any animation. This created a jarring visual discontinuity where code seemed to "buffer" and then dump all at once, while surrounding text streamed smoothly.

Changes

  • packages/streamdown/lib/animate.ts: Added SKIP_TAGS_WITHOUT_CODE set, made hasSkipAncestor state-aware, added animateCodeBlocks flag to render state, exposed setAnimateCodeBlocks on the plugin API
  • packages/streamdown/index.tsx: Block component calls animatePluginProp.setAnimateCodeBlocks(isIncomplete) to enable code animation for blocks with unclosed fences

Test plan

  • All 982 existing tests pass
  • Animate-specific tests pass (32 tests)
  • Incomplete code block tests pass (35 tests)
  • Biome linter passes with no issues
  • Manual verification: stream a markdown response containing a fenced code block and confirm content appears incrementally with animation

Fixes #473

This contribution was developed with AI assistance (Claude Code).

When using the `animated` prop, the animate plugin skipped all code/pre
elements. This meant code block content appeared instantly while surrounding
prose faded in word-by-word, creating a visual "buffering" effect where
code seemed to dump all at once instead of streaming incrementally.

The fix adds a `setAnimateCodeBlocks` method to the animate plugin. When
a block has an incomplete (unclosed) code fence, the Block component tells
the animate plugin to include code/pre elements in its animation pass.
Once the code fence closes, animation reverts to the default behavior of
skipping code blocks (since completed code gets syntax highlighting).

Fixes vercel#473

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Contributor

vercel bot commented Mar 22, 2026

@mvanhorn is attempting to deploy a commit to the Vercel Team on Vercel.

A member of the Team first needs to authorize it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fenced code blocks don't render incrementally during streaming

1 participant