MarkdownView
SignalX-native, streaming-aware markdown renderer. Parses markdown in JS and renders to Lynx primitives — identical on iOS, Android, and Harmony, with no native module.
Import
import { MarkdownView } from '@sigx/lynx-markdown';
MarkdownView lives on the package root, which pulls in no runtime peers — renderer-only consumers pay nothing and have nothing to prebuild.
Basic usage
value is the markdown source and the only prop you usually need. It is reactive: pass a signal's value and the view re-renders as the source grows.
import { MarkdownView } from '@sigx/lynx-markdown';
function Doc() {
return (
<MarkdownView value={'# Hello\n\nThis is **markdown** rendered to native views.'} />
);
}
Supports CommonMark + GFM: headings, bold/italic/strike, inline code, links, images, autolinks, nested ordered/unordered lists, GFM task lists, blockquotes, fenced code, thematic breaks, and tables with per-column alignment. Unsupported constructs (raw HTML, reference-style links, setext headings, syntax highlighting) render as literal text rather than throwing.
Handling link and image taps
The default renderers never navigate on their own — wire onLink and onImageTap to act on taps. Hrefs are sanitized first: only http(s):, mailto:, tel:, and scheme-less links reach onLink; javascript:/data: collapse to #.
import { MarkdownView } from '@sigx/lynx-markdown';
function Article(props: { source: string }) {
return (
<MarkdownView
value={props.source}
onLink={(href) => openInBrowser(href)}
onImageTap={(src) => showLightbox(src)}
/>
);
}
The default image renderer shows the alt text (or src) as a tappable link, not a real <image> — supply your own image component via components for inline pictures.
Streaming AI output
Pair MarkdownView with createMarkdownStream to render a token loop flicker-free: finalized blocks keep stable keys and are never re-parsed or remounted, so completed paragraphs and code blocks never reflow.
import { MarkdownView, createMarkdownStream } from '@sigx/lynx-markdown';
const stream = createMarkdownStream({ flushIntervalMs: 16 });
async function generate(prompt: string) {
stream.reset();
for await (const token of askModel(prompt)) stream.append(token);
stream.done();
}
function ChatBubble() {
return <MarkdownView value={stream.value.value} />;
}
Theming with a component map
MarkdownView is design-system agnostic. It ships neutral defaultComponents and merges your partial components map over them — any node type you omit falls back to the default. Block renderers return a JSXElement; inline renderers return a MarkdownChild (a JSX element or a string).
import { MarkdownView } from '@sigx/lynx-markdown';
const components = {
heading: (p) => (
<text style={{ fontSize: p.level === 1 ? 28 : 20, fontWeight: 'bold' }}>
{p.children}
</text>
),
strong: (p) => <text style={{ fontWeight: 'bold', color: '#7c3aed' }}>{p.children}</text>,
};
function Themed(props: { source: string }) {
return <MarkdownView value={props.source} components={components} />;
}
For a ready-made theme, @sigx/lynx-daisyui exports markdownComponents — a complete daisyUI-styled map you can pass straight to components.
Mention previews via a parser extension
MarkdownView is not plugin-aware, but it accepts raw parser extensions plus an extension component map, so you can render plugin syntax in read-only output. To show @[label](id) chips, pass the standalone mentionSyntax extension and map its node to the plugin's preview component.
import { MarkdownView, createMentionPlugin, mentionSyntax } from '@sigx/lynx-markdown';
const plugin = createMentionPlugin({ search: (q) => findPeople(q) });
const components = { extension: { mention: plugin.inline.component } };
const extensions = [mentionSyntax] as const;
function Transcript(props: { source: string }) {
return <MarkdownView value={props.source} extensions={extensions} components={components} />;
}
Keep
extensionsa stable array reference (a module constant, not an inline literal). Changing its identity recreates the parse engine and re-parses from scratch, defeating the incremental streaming optimization.
Props
All props are optional.
| Prop | Type | Description |
|---|---|---|
value | string | The markdown source. Reactive and parsed incrementally. |
onLink | (href: string) => void | Called with a sanitized href when a link is tapped. |
onImageTap | (src: string) => void | Called with the image src when an image is tapped. |
components | Partial<MarkdownComponents> | Per-node render overrides, merged over defaultComponents. |
extensions | readonly ParserInlineExtension[] | Stable array of inline parser extensions (e.g. mentionSyntax). |
See the API reference for the full MarkdownComponents map and the parser/AST types.
