vssvelte streamdown.
Two Svelte 5 Renderers Built for AI Streaming
at a glance.
Compare svelte-streamdown and @humanspeak/svelte-markdown: two Svelte 5 markdown renderers for streaming AI output, with different approaches to styling, caching, HTML, MDX, and rich content.
side-by-side.
Every surface that matters, compared without spin.
| feature | @humanspeak/svelte-markdown | Svelte Streamdown |
|---|---|---|
| Svelte 5 Compatibility | yes | yes |
| TypeScript Support | yes | yes |
| Streaming API Svelte Markdown can consume transport deltas directly. With Svelte Streamdown, the application maintains and repeatedly supplies the accumulated content string. | Reactive source or direct writeChunk() ingestion | Reactive complete-content prop |
| Out-of-Order Chunk Delivery Svelte Markdown accepts writeChunk({ value, offset }) and assembles websocket-style chunks even when they arrive out of order. Svelte Streamdown accepts a complete content string, so callers must order and assemble chunks before updating the prop. | Native offset-addressed chunk assembly | no |
| Mid-Stream Corrections Offset-addressed writes support retransmission, transcription correction, and edits to previously received output without requiring callers to reconstruct the complete document first. | Offset writes can replace earlier ranges | Caller rebuilds the content string |
| Stream Lifecycle Isolation Svelte Markdown provides synchronous resetStream() and declarative streamId boundaries to prevent content from one response carrying into the next. | resetStream() + streamId | Caller-managed content state |
| Incomplete Markdown Both projects are designed to keep partial AI output renderable while new content arrives. | yes | yes |
| Streaming HTML Output Svelte Markdown explicitly tracks incomplete raw HTML tails; Svelte Streamdown documents graceful handling for incomplete markdown and MDX blocks. | Partial blocks reconcile when </tag> arrives | Incomplete blocks handled |
| Repeated Document Cache Svelte Streamdown caches block splitting and uses Svelte reactivity to reuse unchanged mounted blocks, but does not provide a reusable LRU for completed documents that are revisited or remounted. | Built-in configurable LRU + TTL | no |
| Append-Only Stream Reuse Both avoid needlessly parsing stable content. Svelte Markdown additionally coalesces bursts of incoming updates at the animation-frame boundary. | Tail-window parser + frame coalescing | Cached block splitting + reactive block reuse |
| Measured Streaming Performance Measured against svelte-streamdown 4.2.0 on 2026-09-22 in production Chromium 151: append-only cumulative-prop updates with animation, controls and highlighting off; two suites, each with one warmup and five measured iterations per renderer/scenario. Streamdown / Svelte Markdown median completion-time ratios: 4.47–5.03 for 10 KB tiny chunks (10,059 bytes, 16-character chunks); 4.79–5.65 for 50 KB small chunks (50,153 bytes, 64-character chunks); 7.13–9.09 for 200 KB medium chunks (200,237 bytes, 256-character chunks). KB sizes are minimum targets. With one 512-character update per frame over 50,153 bytes, both sustained about 60 updates/s (ours 60.274–60.315; Streamdown 60.438–60.629), with Streamdown slightly lower elapsed medians. These observations apply to these workloads, not pure parsing or imperative chunk ingestion. Reproduce with pnpm perf:stream-compare. | Lower measured burst medians; ~60 frame-paced updates/s | Higher measured burst medians; ~60 frame-paced updates/s |
| Measured DOM Footprint (50 KB) Freshly measured against svelte-streamdown 4.2.0 on 2026-09-22 in production Chromium 151 using the actual 50,153-byte corpus (50 KB minimum target), append-only cumulative-prop updates, and animation, controls and highlighting off. Two suites, each with one warmup and five measured iterations per renderer/scenario: counts were stable across all 20 measured runs per renderer combining 64-character burst chunks and 512-character frame-paced chunks. Svelte Markdown used about 19% fewer descendant elements (2,821 versus 3,480); these counts measure elements, not all DOM nodes or memory. Matching semantic content was verified; table/list whitespace and code wrappers differ. | 2,821 descendant elements | 3,480 descendant elements |
| Custom Renderers | 24 markdown + 83 HTML snippet overrides | Typed snippets + theme system |
| HTML Tag Control | 83 tags with allow/deny helpers | skipHtml + allowed element controls |
| URL Safety Defaults The default ["*"] permits HTTP/HTTPS URLs across origins and mailto:/tel: links; it blocks javascript:, data:, and vbscript:. Prefix lists can restrict destinations further. | Protocol allowlist + attribute sanitization | Configurable prefixes + default protocol allowlist |
| Streaming Animations | no | Word, character, or block animations |
| MDX-Style Components | no | yes |
| Inline Citations | no | Popover + list/carousel views |
| Built-in Styling | Unstyled by default | Tailwind typography + themes |
| Math (KaTeX) | Opt-in first-class extension | Opt-in component |
| Diagrams (Mermaid) | Opt-in first-class extension | Opt-in interactive component |
| Code Highlighting | Opt-in Shiki extension | Opt-in @tanstack/highlight component + copy button |
| Marked Extensions | Full extension objects | Custom tokenizers |
| Advanced Tables | GFM tables | GFM + row/column spans, footers, multiple headers |
where each shines.
- +Svelte 5 runes-native — built for runes, not retrofitted
- +TypeScript-first with full type safety
- +Built-in token caching (50-200x faster re-renders on repeated content)
- +LLM streaming with imperative writeChunk() / resetStream() API
- +24 markdown renderers + 83 HTML tag renderers — every override is a Svelte snippet
- +First-class extensions: KaTeX math, Mermaid diagrams, GitHub alerts, footnotes
- +Opt-in Shiki syntax highlighting (streaming-compatible, tree-shaken from core)
- +Built-in XSS protection — protocol allowlist, event-handler stripping, attribute sanitization
- +Allow/deny utilities (allowHtmlOnly, excludeRenderersOnly, etc.) for fine-grained control
- +Drop-in component — works anywhere in your Svelte app
- +Direct transport-delta ingestion without maintaining a second reactive accumulator
- +Native out-of-order chunk assembly with offset-addressed writes
- +Mid-stream replacement writes for corrections and retransmission
- +Explicit resetStream() and streamId lifecycle boundaries
- +Lower median completion times than svelte-streamdown 4.2.0 in each measured burst workload (10/50/200 KB minimum targets; 2026-09-22)
- +About 19% fewer descendant elements than svelte-streamdown 4.2.0 on the freshly measured 50,153-byte corpus (2026-09-22; animation, controls and highlighting off)
- +Configurable LRU cache also accelerates repeated non-streaming documents
- +Broad raw HTML support with per-tag renderers and allow/deny helpers
- +Default URL and attribute sanitizers with customizable hooks
- +Unstyled core integrates without requiring Tailwind
- +Purpose-built streaming animations at word, character, and block level
- +MDX-style custom Svelte components inside runtime markdown
- +Interactive citations with popover, list, and carousel presentations
- +Opinionated typography and granular Tailwind theme system out of the box
- +Rich built-ins including interactive Mermaid controls, code copy buttons, and advanced tables
where each falls short.
- −Smaller community (newer project)
- −Runtime-only (no build-time optimization)
- −No built-in token reveal animations or citation UI
- −No MDX-style component syntax inside markdown
- −Requires application styling by design
- −No imperative chunk-ingestion API — callers update the complete content string
- −No native offset-addressed assembly for out-of-order chunks or earlier-range corrections
- −Stream resets and response isolation are managed in caller-owned content state
- −No reusable LRU cache for switching among previously rendered documents
- −Opinionated styling requires Tailwind setup or theme overrides
- −A newer, single-maintainer port that tracks the upstream React project
the honest call.
Choose Svelte Streamdown when you want a batteries-included AI response UI with animated reveals, citations, MDX-style components, interactive diagrams, and Tailwind styling. Choose @humanspeak/svelte-markdown when you want a lower-level, unstyled renderer with direct and out-of-order chunk ingestion, explicit stream lifecycle controls, frame-coalesced updates, reusable document caching, broad raw-HTML customization, and configurable URL and attribute sanitization. Both are credible Svelte 5 choices for incomplete streaming markdown; the deciding factor is whether you want an opinionated presentation layer or a composable rendering primitive.
read more.
Every head-to-head, with the same matrix + pros / cons + verdict format.
Build-Time Preprocessor vs Runtime Component
read comparison ↗Do you need to edit markdown, or just render it?
read comparison ↗Raw Parser vs Svelte Component
read comparison ↗The Engine Under Our Hood
read comparison ↗Plugin-Driven Editor vs Focused Renderer
read comparison ↗Two Runtime Renderers, Different Engines
read comparison ↗Editor + Viewer vs Pure Renderer
read comparison ↗Full Editor vs Pure Renderer
read comparison ↗AST Pipeline vs Component Renderer
read comparison ↗Editor Toolkit vs Ready-Made Renderer
read comparison ↗The full /compare index — every head-to-head in one place.
browse all ↗svelte markdown → install in 30 seconds