Enhanced Unterminated Block Parsing
vue-stream-markdown implements powerful unterminated block parsing capabilities internally, inspired by remend from the streamdown project. vue-stream-markdown implements similar functionality with more aggressive optimizations specifically for streaming scenarios.
Enhanced Features
vue-stream-markdown extends the remend-inspired functionality with enhanced handling for footnotes, links, images, tables, math, and syntax trimming. These enhancements provide better visual feedback and prevent broken interactions during streaming.
Footnotes
vue-stream-markdown removes incomplete footnote references ([^label]) that don't have corresponding definitions ([^label]:). This prevents broken footnote references from appearing during streaming, especially when the definition hasn't arrived yet.
Incomplete footnote reference (removed):
> "Knowledge is power—but digital knowledge is acceleration."[^1]"Knowledge is power—but digital knowledge is acceleration."
Complete footnote (kept):
> "Knowledge is power—but digital knowledge is acceleration."[^1]
[^1]: Definition of the quote1."Knowledge is power—but digital knowledge is acceleration." [1]
Definition of the quote
How It Works
- Reference removal: Removes footnote references (
[^label]) that don't have a corresponding definition ([^label]:) in the entire content - Incomplete reference handling: Also removes incomplete references like
[^1(missing closing bracket) - Code block awareness: Ignores footnote references inside code blocks (both fenced code blocks and inline code)
- Definition detection: Scans the entire content to find all footnote definitions before processing references
Links
Unlike the original remend approach which extracts link text and displays it as plain text, vue-stream-markdown completes the link syntax while intelligently disabling click interactions:
Incomplete link (loading state):
[Click here to visitComplete link:
[Click here](https://example.com)How It Works
- During streaming: The link syntax is completed, but the link is rendered with
pointer-events: noneand no underline, preventing broken navigation - When complete: The link becomes fully interactive with an underline, indicating it's ready to be clicked
- Visual feedback: Users can see the link structure forming, but can't accidentally click on incomplete links
- Trailing bracket removal: Standalone
[orHow It Works
- During streaming: The image syntax is completed and a loading spinner is displayed
- When complete: The image loads normally with proper error handling
- Better UX: Users see visual feedback that an image is coming, rather than nothing at all
Tables
vue-stream-markdown proactively completes table syntax and provides a loading state, ensuring smooth rendering even when the table structure is incomplete:
Incomplete table:
| Name | Age | City |
| John | 25 | New| Name | Age | City |
|---|---|---|
| John | 25 | New |
Complete table:
| Name | Age | City |
| --- | --- | --- |
| John | 25 | New York |
| Jane | 30 | San Francisco || Name | Age | City |
|---|---|---|
| John | 25 | New York |
| Jane | 30 | San Francisco |
How It Works
- Header detection: Automatically detects table headers and completes them if needed
- Separator generation: Generates the separator row (
| --- | --- |) when a header is detected - Column matching: Ensures the separator matches the number of columns in the header
- Loading state: Provides visual feedback during table construction
Inline Math
The original remend approach doesn't handle inline KaTeX with single $ as they're likely currency symbols. vue-stream-markdown attempts to complete inline math syntax, providing better support for mathematical expressions in streaming content:
Incomplete inline math (partial rendering):
The quadratic formula is $$x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a$The quadratic formula is
Complete inline math:
The quadratic formula is $$x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}$$The quadratic formula is
How It Works
- Pattern detection: Detects incomplete
$$...$$patterns in the last paragraph - Block vs inline: Distinguishes between inline math (
$$...$$on same line) and block math ($$on separate lines) - Code block awareness: Ignores math syntax inside code blocks
- Smart completion: Only completes when there's actual content after the opening
$$
Syntax Trimming
For syntax characters like `, *, _ that often indicate the start of a syntax block, vue-stream-markdown attempts to trim them when they appear at the end of content, reducing visual artifacts during streaming:
Example:
Here is some text with a trailing ```Result:
Here is some text with a trailing
How It Works
- Trailing detection: Identifies incomplete syntax sequences at the end of content
- Smart removal: Removes trailing backticks (
, ``, ```) when they have no content - Visual cleanup: Prevents showing intermediate states like `, ``, or ``` at the end of content
- Context aware: Only trims when appropriate, preserving valid syntax
Streaming Examples
Footnote Streaming
As content streams in, incomplete footnote references are removed until their definitions appear:
Text [^1]→Text(reference removed if definition doesn't exist)Text [^1→Text(incomplete reference removed)Text [^1]\n\n[^1]: Definition→Text [^1]\n\n[^1]: Definition(reference kept when definition exists)
Link Streaming
As content streams in, incomplete links render with loading state (no underline, non-clickable), then become fully interactive when complete:
[Click here→ Loading state (non-clickable)[Click here](https://example.com)→ Fully clickable with underlineText [→Text(standalone bracket removed)Text [\n→Text(standalone bracket and trailing newline removed)
Image Streaming
Incomplete images show a loading spinner, then load normally when complete:
→ Image loads normally
Table Streaming
| Name | Age→ Completes header and adds separator row| Name | Age |\n| --- | --- |→ Table structure ready| Name | Age |\n| --- | --- |\n| John | 25→ Table renders with data
Inline Math Streaming
Incomplete inline math expressions are completed and rendered with partial content visible:
The quadratic formula is $$x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a$→ Completes and renders partially (missing closing$)The quadratic formula is $$x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}$$→ Renders complete formula
Acknowledgments
This project is inspired by streamdown and the remend library for their foundational ideas on streaming Markdown parsing.