React component library for rendering interactive MarkdownFlow documents with typewriter effects, real-time streaming, and advanced Mermaid diagram support.
MarkdownFlow (also known as MDFlow or markdown-flow) extends standard Markdown with AI to create personalized, interactive pages. Its tagline is "Write Once, Deliver Personally".
English | 简体中文
npm install markdown-flow-ui
# or
yarn add markdown-flow-ui
# or
pnpm add markdown-flow-uiimport { MarkdownFlow } from "markdown-flow-ui";
function App() {
return (
<MarkdownFlow
initialContentList={[
{
content:
"# Hello World\n\nThis is **MarkdownFlow** with typewriter effect!",
},
]}
enableTypewriter={true}
typingSpeed={30}
/>
);
}With the typewriter enabled, prose follows the configured typing pace. Received
HTML waits until the preceding prose has finished typing, then renders each
received snapshot immediately, including unfinished fragments. HTML does not consume
the typing budget. Tag-like text such as <div
remains ordinary Markdown until a tag-name boundary (whitespace, /, or >) is
received.
Streaming detection recognizes the backend MarkdownFlow block roots, including
figure, table, canvas, video, header, nav, and details. HTML-looking
text inside Markdown code, math, comments, image alt text, link destinations/titles,
reference definitions, or another tag's attributes stays inert. Unfinished link metadata
also stays literal while streaming; invalid links do not hide subsequent HTML.
Quoted and nested list code fences remain code even directly after closed HTML.
Detection and presentation are separate: pre, details, summary,
aside, blockquote, ul, ol, dl, and table keep their native Markdown
styles and language/direction attributes while bypassing typing. Widget roots
retain the sandbox; native presentation blocks with embedded script, style, or
other document resources also use the sandbox (native video frames are exempt).
In content mode, sandbox blocks reserve their measured content height instead
of a minimum 16:9 slide. The iframe retains a separate layout viewport of at
least 16:9 so authored vh and vmin sizes stay stable; unused viewport space
is clipped by the top-aligned content container. Content growth, collapse,
image loads and width changes trigger remeasurement. When shown, the fullscreen
control reserves its actual height so it remains accessible on very short blocks.
Full-screen minimum heights (min-height:100vh, 100dvh, 100svh, or 100lvh)
on inline-styled content shells and their single-child wrapper chains are relaxed
so compact cards do not reserve a blank screen. Authored margins, padding, pixel
minimums, explicit heights (including height:100vh) and viewport-relative fonts
remain intact. Nested layout branches are not rewritten.
Blackboard sizing and sandbox permissions are unchanged.
Detection scans absolute source offsets without reparsing every remaining
suffix. Native videos use the complete received Markdown structure; typing only
changes text visibility, preserving video frames across earlier headings, lists,
quotes, reference links, and subsequent HTML updates. Stable runs apply the
same HTML indentation and newline normalization as the ordinary renderer, with
positions mapped back to the original source for typing and callbacks.
Each received snapshot determines the Markdown structure. Later source that
changes its grammar, such as adding a previously missing reference definition,
can change that structure; typing an already received snapshot preserves it.
import { MarkdownFlow } from "markdown-flow-ui";
function InteractiveExample() {
const content = `
Choose your language: ?[%{{lang}} English | 中文 | Español]
Your name: ?[%{{name}} Enter your name...]
?[Continue | Cancel]
`;
return (
<MarkdownFlow
initialContentList={[{ content }]}
onSend={(params) => {
console.log("User interaction:", params);
// Handle button clicks and input submissions
}}
/>
);
}For detailed API documentation, examples, and advanced usage, see:
📋 API Reference - Complete API documentation with examples
const CustomBar: CustomRenderBarProps = ({ displayContent, onSend }) => {
return (
<div className="flex gap-2 mt-4">
<button
onClick={() => onSend({ buttonText: "Regenerate" })}
className="px-4 py-2 bg-blue-500 text-white rounded"
>
Regenerate
</button>
<button
onClick={() => navigator.clipboard.writeText(displayContent)}
className="px-4 py-2 bg-gray-500 text-white rounded"
>
Copy
</button>
</div>
);
};
<MarkdownFlow customRenderBar={CustomBar} initialContentList={messages} />;Run npm test for unit tests and npm run test:package for distribution checks.
The package check rebuilds the library before testing both exported stylesheets,
scroll-control visibility and accessibility rules, and bundled math fonts.
CI runs both commands alongside the Storybook browser tests.
markdown-flow-ui is part of the MarkdownFlow ecosystem for creating personalized, AI-driven interactive documents:
- markdown-flow - The main repository containing homepage, documentation, and interactive playground
- markdown-flow-agent-py - Python agent for transforming MarkdownFlow documents into personalized content
- markdown-it-flow - markdown-it plugin to parse and render MarkdownFlow syntax
- remark-flow - Remark plugin to parse and process MarkdownFlow syntax in React applications
MIT License - see LICENSE file for details.
- React Markdown for markdown processing
- Mermaid for diagram rendering
- Highlight.js for syntax highlighting
- Tailwind CSS for styling
- Radix UI for accessible components