composed · Composed pattern
MarkdownViewer
@devalok/shilp-sutra/composed/markdown-viewerView in Storybook Hand-curated previews ship in rolling waves. See it live in Storybook →
Reference
Props
content: string (markdown source)
compact: boolean (tighter spacing for inline use)
allowHtml: boolean (allow raw HTML in markdown)
linkTarget: string (target attribute for links)
Defaults
compact={false}, allowHtml={false}, linkTarget="_blank"
Example
<MarkdownViewer content={message.body} />
<MarkdownViewer content={comment} compact />
<MarkdownViewer content={trustedHtml} allowHtml />
Composability
- Read-only markdown renderer. For editing, use RichTextEditor (TipTap-based). MarkdownViewer is strictly for display.
- Built on react-markdown + remark-gfm — GFM tables, strikethrough, task lists supported out of the box.
- Syntax highlighting is lazy: Code blocks with a language fence (
ts,python) lazy-load react-syntax-highlighter. First render shows a plain<pre>fallback. Don't pre-import. - Security posture: Raw HTML is stripped by default —
allowHtml={true}must be explicit, and ONLY for trusted content (XSS vector otherwise). - Links open external by default (
target="_blank"+rel="noopener noreferrer"). Override vialinkTarget. - compact mode for inline use (comments, message bubbles). Default spacing is for article-body content.
- Pairs with Chat's Message.Body — render markdown from user messages safely. Always keep
allowHtml={false}for user-generated content.
Gotchas
- Code blocks with a language fence are syntax-highlighted via
react-syntax-highlighter(lazy-loaded) — the first render shows a plain<pre>fallback - GFM (tables, strikethrough, task lists) is supported via
remark-gfm - Raw HTML is stripped by default — only enable
allowHtmlfor trusted content - Links open in a new tab by default (
target="_blank"withrel="noopener noreferrer")