Skip to main content
Streamdown exports several standalone utility functions and hooks from the streamdown package. These are useful when building custom streaming UIs, pre-processing content before rendering, or integrating Streamdown features into your own components.

parseMarkdownIntoBlocks()

function parseMarkdownIntoBlocks(markdown: string): string[]
Splits a Markdown document into an array of top-level block strings using the marked lexer. Each element in the returned array corresponds to one logical block (paragraph, heading, code fence, list, blockquote, HTML block, etc.). Streamdown uses this function internally to split content into independently memoised React nodes, which allows only the last (incomplete) block to re-render as new tokens arrive during streaming.
markdown
string
required
The Markdown source string to split.
Returns string[] — an array of block strings. Each block retains its original whitespace and newlines.

Special cases

  • Footnotes — if the document contains any footnote references ([^1]) or definitions ([^1]: ...), the entire document is returned as a single block. Footnote references and definitions must share the same mdast tree to resolve correctly.
  • Math blocks — consecutive blocks are merged when the accumulated text contains an odd number of $$ markers (indicating an unclosed block math expression). This handles cases where marked’s lexer splits math blocks across multiple tokens.
  • HTML blocks — consecutive tokens are merged when they are inside an unclosed HTML tag pair, tracking nesting depth to avoid premature closure.

Example

import { parseMarkdownIntoBlocks } from "streamdown";

const blocks = parseMarkdownIntoBlocks(`
# Hello

This is a paragraph.

\`\`\`python
print("hello")
\`\`\`
`);

// blocks[0] → "# Hello\n\n"
// blocks[1] → "This is a paragraph.\n\n"
// blocks[2] → "```python\nprint(\"hello\")\n```\n"

Custom block parser

You can replace the built-in block parser by passing parseMarkdownIntoBlocksFn to <Streamdown>:
<Streamdown
  parseMarkdownIntoBlocksFn={(md) => [md]}
>
  {markdown}
</Streamdown>

normalizeHtmlIndentation()

function normalizeHtmlIndentation(content: string): string
Removes four or more leading spaces or tabs before HTML tags at line starts. This prevents the Markdown parser from interpreting indented HTML blocks as fenced code blocks — a common issue with AI-generated HTML that uses deep indentation for readability.
content
string
required
The raw HTML/Markdown string to process.
Returns the normalised string. If the content does not start with an HTML-like tag (after optional whitespace), it is returned unchanged immediately.
This function is a no-op unless the content starts with an HTML tag. It only strips indentation from lines where the first non-whitespace content is an HTML tag — regular Markdown content is not affected.

Usage

Enable normalisation on <Streamdown> with the normalizeHtmlIndentation prop (disabled by default):
<Streamdown normalizeHtmlIndentation>
  {aiGeneratedHtml}
</Streamdown>
Or call the function directly:
import { normalizeHtmlIndentation } from "streamdown";

const normalized = normalizeHtmlIndentation(content);

detectTextDirection()

function detectTextDirection(text: string): "ltr" | "rtl"
Detects the text direction of a Markdown string using the first strong character algorithm. Common Markdown syntax (headings, bold/italic markers, inline code, links, list markers, and blockquotes) is stripped before the first Unicode letter with strong directionality is located.
text
string
required
The Markdown string to analyse.
Returns "rtl" if the first strong directional character falls in a right-to-left Unicode range (Hebrew, Arabic, Syriac, Thaana, NKo, Samaritan, Mandaic, Arabic Supplement/Extended, or RTL presentation forms). Returns "ltr" otherwise, including when no directional character is found.

Usage with Streamdown

Pass dir="auto" to <Streamdown> to enable per-block direction detection:
<Streamdown dir="auto">
  {markdown}
</Streamdown>
Each block’s direction is determined independently using detectTextDirection. The detected direction is applied as the dir attribute on a display: contents wrapper <div>.

Example

import { detectTextDirection } from "streamdown";

detectTextDirection("Hello, world!");     // → "ltr"
detectTextDirection("שלום, עולם!");       // → "rtl"
detectTextDirection("## مرحبا بالعالم");  // → "rtl" (heading stripped before detection)

useIsCodeFenceIncomplete()

function useIsCodeFenceIncomplete(): boolean
A React hook that returns true when the code fence in the current block has not yet been closed — i.e. Streamdown is actively streaming content into it. This hook reads from BlockIncompleteContext, which is set by the Block component. It is only meaningful inside components rendered within a Streamdown Block.

When to use

Use this hook inside a custom renderer (via plugins.renderers) or a component rendered inside a code block to defer expensive operations until the code is complete:
import { useIsCodeFenceIncomplete } from "streamdown";

const MermaidRenderer = ({ code }: { code: string }) => {
  const isIncomplete = useIsCodeFenceIncomplete();

  if (isIncomplete) {
    // Don't attempt to render partial Mermaid syntax
    return <pre>{code}</pre>;
  }

  return <MermaidDiagram source={code} />;
};
The isIncomplete prop on CustomRendererProps carries the same value as this hook and is available directly in custom renderers without needing to call the hook.

Build docs developers (and LLMs) love