remend is a pre-processor for streaming Markdown text. As an LLM streams tokens, it produces a string that may end mid-way through a formatting construct — an unclosed **, a partial link [text](, or a dangling $ — which would cause the downstream Markdown parser to misinterpret the entire document. remend scans the text and applies a prioritised chain of fixup handlers before the string reaches the parser.
Streamdown applies remend automatically in mode="streaming" when parseIncompleteMarkdown={true} (the default). The remend prop on <Streamdown> forwards RemendOptions directly.
Installation
Usage
Standalone example
Default export: remend()
The raw streaming Markdown text to process.
Optional configuration. When omitted, all built-in handlers except
inlineKatex are enabled with their default behaviour.text is empty or not a string, it is returned unchanged.
RemendOptions
All options default totrue (enabled) unless stated otherwise. Set an option to false to disable that specific handler.
Complete incomplete bold markers.
**text → **text**. Default: true.Complete incomplete bold-italic markers.
***text → ***text***. Default: true.Complete incomplete italic markers for
*, _, and __ variants. Default: true.Complete an unclosed inline code span.
`code → `code`. Default: true.Complete incomplete strikethrough markers.
~~text → ~~text~~. Default: true.Fix incomplete link syntax.
[text](url → [text](streamdown:incomplete-link). Default: true.Fix incomplete image syntax. Enables the links handler when set to
true. Default: true.Controls how incomplete links are handled.
"protocol" (default) replaces the partial URL with streamdown:incomplete-link. "text-only" removes the link markup entirely, leaving only the display text.Complete an incomplete block KaTeX expression.
$$equation → $$equation$$. Default: true.Complete an incomplete inline KaTeX expression.
$equation → $equation$. Default: false — a single $ is ambiguous with currency and this handler is opt-in.Escape a single
~ between word characters to prevent false strikethrough. 20~25 → 20\~25. Default: true.Prevent incomplete setext headings (e.g. a line ending with
--- that the parser would interpret as an <h2>) from being misrenderd during streaming. Default: true.Escape
> as a comparison operator inside list items (e.g. - > 25 → - \> 25) to prevent the > from being interpreted as a blockquote. Default: true.Strip incomplete HTML tags at the end of streaming text (e.g.
text <custom → text). Default: true.Additional custom handlers to include in the pipeline. Custom handlers run after all enabled built-in handlers unless you set a lower
priority.RemendHandler
The interface for a custom handler added viaoptions.handlers.
A unique identifier for this handler. Used for debugging and deduplication.
The transformation function. Receives the current text (after all higher-priority handlers have run) and returns the modified text.
Execution order relative to other handlers. Lower values run first. Built-in handler priorities range from
0 to 100. Custom handlers default to 100 when this field is omitted.Built-in priorities for reference:| Handler | Priority |
|---|---|
singleTilde | 0 |
comparisonOperators | 5 |
htmlTags | 10 |
setextHeadings | 15 |
links | 20 |
boldItalic | 30 |
bold | 35 |
italic (double underscore) | 40 |
italic (single asterisk) | 41 |
italic (single underscore) | 42 |
inlineCode | 50 |
strikethrough | 60 |
katex | 70 |
inlineKatex | 75 |
| default (custom) | 100 |
Named exports
The following utility functions are exported for use in custom handlers or other preprocessing logic.isWithinCodeBlock()
true if position falls between a pair of triple-backtick fences in text. Useful for skipping transformations that should not affect code block contents.
isWithinMathBlock()
true if position is inside an inline $...$ or block $$...$$ math expression. Handles escaped dollar signs (\$) and the precedence of block math over inline math.
isWithinLinkOrImageUrl()
true if position is inside the URL portion (...) of a Markdown link or image — i.e. between ]( and ). Useful for preventing transformations inside URLs.
isWordChar()
true if char is a word character: ASCII letters (a-z, A-Z), digits (0-9), underscore (_), or any Unicode letter-or-number character outside ASCII. Uses an ASCII fast path before falling back to a Unicode regex.