EXEPERTAI LAB

Research alpha

Time Machine
EXEPERTAI LAB
GALLERY / COLLECTION
← Browse Astryx gallery
Markdown·component·@astryxdesign/core

Markdown

Renders a markdown string as Astryx-styled components. Use Markdown for user-generated content, AI responses, and documentation; it handles headings, lists, tables, code blocks, and citations with consistent styling.

Open in Playground @astryxdesign/core/Markdown

Showcases and examples

5 documented examples

Markdown

Rich markdown content with headings, lists, and formatting.

Preview loads on approachPreview loads on approach
Exact source · markdown-showcase
// Copyright (c) Meta Platforms, Inc. and affiliates.

'use client';

import {Markdown} from '@astryxdesign/core/Markdown';
import {Center} from '@astryxdesign/core/Center';

const content = [
  '# Markdown Demo',
  '',
  'Renders **markdown** with *design-system-consistent* styling.',
  '',
  '## Features',
  '',
  '- Headings mapped to the Astryx type scale',
  '- **Bold**, *italic*, and ~~strikethrough~~ text',
  '- [Links](https://example.com) with external detection',
  '',
  '> Block quote indented text',
].join('\n');

export default function MarkdownShowcase() {
  return (
    <Center width={400}>
      <Markdown>{content}</Markdown>
    </Center>
  );
}

Usage

Renders a markdown string as Astryx-styled components. Use Markdown for user-generated content, AI responses, and documentation; it handles headings, lists, tables, code blocks, and citations with consistent styling.

  • Set headingLevelStart to match the page hierarchy, e.g. start at 3 if the markdown sits inside an h2 section.
  • Use contentWidth to keep prose at a readable line length in wide layouts.
  • Use plugins created by createMarkdownPlugin for reusable syntax, immutable AST transforms, and typed extension rendering. Keep the ordered list stable while its syntax configuration is unchanged.
  • Add markdownSoftBreaksPlugin when single line endings are meaningful. It matches remark-breaks for supported Markdown, including multiline link labels, while code and other opaque content stay unchanged.
  • Use createMarkdownTextTransform for prose matching; it preserves code, links, images, citations, math, and accepted extension syntax as protected contexts. Provide requiredSubstrings only when they conservatively cover every possible match.
  • Use createMarkdownFenceTransform for declared code-fence languages with semantic data. createNode returns an owned block extension node; its standard plugin renderer and toText own presentation. components.code still wins, and a declined or failed proposal keeps the accessible, copyable CodeBlock fallback.
  • Use createMarkdownSourceDecoration to attach non-visual metadata — search hits, review annotations — to the blocks a source range touches, and getMarkdownSourceDecorations to read it back in a later plugin. Decorations appear on the settled document rather than on partial streaming chunks, and never change rendering, copyable text, accessible names, ids, focus order, or navigation.
  • Import parseMarkdownAst or parseInlineAst from @astryxdesign/core/Markdown/parser when server or React Server Component code needs to run plugins against the canonical readonly tree. The parser and plugin subpaths have no use-client boundary. The Markdown component remains client-owned, so function-bearing plugin entries must not be passed across an RSC serialization boundary.
  • Use createMarkdownFrontmatter for typed document metadata. Its parse() method gives the host metadata directly; its plugin removes a complete leading block before rendering and withholds an unfinished block during streaming.
  • Import createMarkdownRemarkTransform from '@astryxdesign/core/Markdown/remark' only to reuse an existing synchronous transform-only Remark plugin; it stays out of every other bundle. Prove each plugin with fixtures: anything outside the supported MDAST subset — async work, parser or compiler plugins, processor state, raw HTML, unsupported nodes, forged positions, or metadata Astryx cannot represent — keeps the last valid document and reports one diagnostic.
  • Use inlinePlugins for prefixed identifiers, mentions, and other prose-only shorthand instead of preprocessing the markdown string.
  • Provide components.math only for documents that use dollar-delimited math. The renderer owns typesetting and accessible output; Astryx passes the expression as text and never executes raw HTML.
  • For direct parsing, use MathParseOptions and handle InlineNodeWithMath or BlockNodeWithMath. Incremental math parsing also uses createIncrementalState<true>() and IncrementalParseState<true>; default calls and ParseOptions annotations keep the legacy unions.
  • Pair with Outline and useOutlineFromMarkdown for section navigation: headings render generated id attributes that match the outline item ids, so hash links scroll to their target.
  • Use Markdown for hand-authored layouts; use Text and Heading directly when you control the content.

Typed props

PropType and behavior
childrenstring · required
The markdown string to render.
display'block' | 'inline' · default 'block'
Display type. Markdown defaults to block. Use 'inline' for markdown spans embedded inside text.
density'default' | 'compact' · default 'default'
Controls spacing between block-level elements.
headingLevelStart1 | 2 | 3 | 4 | 5 | 6 · default 1
The HTML heading level that markdown # maps to. Shifts all heading levels down to fit the surrounding page hierarchy. Levels exceeding h6 are clamped to h6.
isStreamingboolean · default false
Enables streaming mode; it uses incremental parsing and a smooth fade-in animation for chunk-by-chunk text delivery.
onLinkClick(href: string, event: MouseEvent) => void | false
Handler for link clicks. Return false to prevent the default navigation behavior. Link destinations in the markdown follow the shared navigation rule described on the Link href prop: a blocked destination renders as plain text and never reaches this handler or a custom link renderer. Image URLs use a separate, stricter policy (every data: URL is rejected).
sourcesRecord<string, MarkdownSource>
Citation sources keyed by ID. When provided, [id] and 【id】 markers in the markdown that match a key are rendered as citation chips.
citationStyle'label' | 'number' · default 'label'
How citations are displayed inline. 'label' shows a chip with source title, icon, and border. 'number' shows a compact numbered badge.
contentWidthnumber | string · default 680
Max width for prose content (paragraphs, headings, lists, blockquotes). Tables and code blocks are unconstrained and can expand to the full container width. Use for readable line lengths in wide layouts.
contentAlign'start' | 'center' · default 'start'
Alignment of prose content within the container when contentWidth is narrower than the available space.
pluginsreadonly MarkdownPluginEntry[]
Ordered extensions created by createMarkdownPlugin(). Plugins may add bounded syntax, immutable typed AST transforms, and typed extension renderers. Use isMarkdownExtensionNode() to narrow extension data observed from other plugins. Renderer callbacks are pure; return a child component when hooks are needed. Omitted and empty lists preserve the released Markdown behavior.
inlinePluginsMarkdownInlinePlugin[]
Transforms regex matches in parsed text nodes into custom inline React elements. Use for prefixed identifiers, mentions, and other shorthand patterns. Inline code, fenced code blocks, and math are unaffected.
autolink'gfm'
Opt-in autolinking of bare URLs and emails. 'gfm' applies GitHub-Flavored Markdown autolink-literal rules: bare https?://..., www...., <scheme:url>, <email>, and user@host all become links. Trailing sentence punctuation and unbalanced trailing close-parens are excluded; matches inside code spans, code blocks, existing links, and image alt text are skipped. Default behavior (option unset) is unchanged.
componentsMarkdownComponents
Custom React component overrides for rendered Markdown elements (code, inlineCode, math, link, heading, paragraph, image, blockquote, hr, citation). Providing math enables $…$ inline and $$…$$ display parsing and receives {value, display}; omit it when dollar text should stay literal.
xstyleStyleXStyles
StyleX styles for layout customization (margins, positioning, sizing). Must be a stylex.create() value, not an inline style object like style={{}}.
classNamestring
CSS class name for the root element. Prefer xstyle for styling; className is provided for integration with non-StyleX systems.
styleCSSProperties
Inline styles for the root element. Prefer xstyle for styling; inline styles bypass StyleX optimization.
data-testidstring
Test selector for automated testing frameworks.

Anatomy

Document · required

Root container for block or inline Markdown content.

Heading · optional

Rendered heading block; a custom heading renderer replaces the default part.

Paragraph · optional

Rendered paragraph block; a custom paragraph renderer replaces the default part.

List · optional

Ordered, unordered, or task-list block rendered from Markdown items.

Code block · optional

Fenced code block; a custom code renderer replaces the default part.

Blockquote · optional

Quoted block; a custom blockquote renderer replaces the default part.

Table · optional

Table block rendered from Markdown rows and columns; its Table child owns horizontal scrolling.

Divider · optional

Horizontal rule block; a custom hr renderer replaces the default part.

Image · optional

Block image or unsafe-URL fallback; a custom image renderer replaces a safe default image.

Theming

Targets

astryx-markdown

Visual props: density

astryx-markdown-heading

Visual props: density, level

astryx-markdown-paragraph

Visual props: density

astryx-markdown-list

Visual props: density

astryx-markdown-codeblock

Visual props: density

astryx-markdown-blockquote

Visual props: density

astryx-markdown-table

Visual props: density

astryx-markdown-hr

Visual props: density

astryx-markdown-image

Visual props: density