Skip to main content

react-rendering

Render Markdown source or a MarkdownDocument with @tanstack/markdown/react using Markdown, renderMarkdownReact, component replacements, and React static SSR. Load for React article components, emitted-tag mappings, pre-parsed documents, custom elements, or renderer parity.

소스 정보

저장소
TanStack/markdown
최근 소스 활동
2026년 10월 1일 02:00
감지된 SKILL.md 언어
영어
스타
428
포크
10

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
react-rendering
description
Render Markdown source or a MarkdownDocument with @tanstack/markdown/react using Markdown, renderMarkdownReact, component replacements, and React static SSR. Load for React article components, emitted-tag mappings, pre-parsed documents, custom elements, or renderer parity.
metadata
{"type":"framework","library":"@tanstack/markdown","framework":"react","library_version":"1.0.0"}
requires
["render-markdown"]
sources
["TanStack/markdown:docs/guides/react.md","TanStack/markdown:docs/reference/react.md","TanStack/markdown:docs/guides/extensions.md","TanStack/markdown:docs/core-concepts/security.md","TanStack/markdown:src/react.ts","TanStack/markdown:tests/ssr-react.test.tsx"]
This skill builds on [render-markdown](../render-markdown/SKILL.md). Read it first for the syntax profile, parser options, AST, and core trust boundaries. # React Rendering ## Setup Render source directly and keep the surrounding semantic element in the application: ```tsx import { Markdown } from '@tanstack/markdown/react' export function Article({ source }: { source: string }) { return ( <article> <Markdown>{source}</Markdown> </article> ) } ``` `Markdown` returns a React fragment. The React adapter requires React 18 or newer. ## Hooks and Components ### Replace emitted links with an application component ```tsx import { Markdown, type MarkdownComponents, } from '@tanstack/markdown/react' const components = { a(props) { const external = props.href?.startsWith('http') ?? false return ( <a {...props} rel={external ? 'nofollow noopener noreferrer' : props.rel} target={external ? '_blank' : props.target} /> ) }, } satisfies MarkdownComponents export function Article({ source }: { source: string }) { return ( <article> <Markdown components={components}>{source}</Markdown> </article> ) } ``` Known intrinsic keys infer their matching React props. Arbitrary extension component tag names remain supported. ### Parse once before repeated React rendering ```tsx import { parseMarkdown } from '@tanstack/markdown/parser' import { Markdown } from '@tanstack/markdown/react' const document = parseMarkdown('# Cached article\n\nRendered from an AST.') export function Article() { return ( <article> <Markdown>{document}</Markdown> </article> ) } ``` Apply parser options and document transforms when creating the document; renderer options cannot retroactively change its structure. ### Render static React markup on the server ```tsx import { renderToStaticMarkup } from 'react-dom/server' import { Markdown } from '@tanstack/markdown/react' const source = '# Server-rendered article' export const html = renderToStaticMarkup( <article> <Markdown>{source}</Markdown> </article>, ) ``` Core static output is tested for structural equivalence with `renderHtml()`. ### Compose through the lower-level node API ```tsx import type { ReactNode } from 'react' import { parseMarkdown } from '@tanstack/markdown/parser' import { renderMarkdownReact } from '@tanstack/markdown/react' const document = parseMarkdown('# Parsed once') export function ArticleBody(): ReactNode { return renderMarkdownReact(document) } ``` Use `renderBlockReact` or `renderInlineReact` only when custom tree composition needs individual public AST nodes. ## Common Mistakes ### HIGH Injecting HTML instead of React nodes Wrong: ```tsx import { renderHtml } from '@tanstack/markdown' export function Article({ source }: { source: string }) { const html = renderHtml(source) return <article dangerouslySetInnerHTML={{ __html: html }} /> } ``` Correct: ```tsx import { Markdown } from '@tanstack/markdown/react' export function Article({ source }: { source: string }) { return ( <article> <Markdown>{source}</Markdown> </article> ) } ``` The HTML-string path bypasses React component replacement and creates an unnecessary trusted-HTML boundary. Source: `docs/guides/react.md` ### HIGH Mapping AST node names instead of tags Wrong: ```tsx import type { ComponentProps } from 'react' import { Markdown } from '@tanstack/markdown/react' function ArticleLink(props: ComponentProps<'a'>) { return <a {...props} data-navigation="article" /> } export function Article() { return ( <Markdown components={{ link: ArticleLink }}> {'Read the [guide](/guide).'} </Markdown> ) } ``` Correct: ```tsx import type { ComponentProps } from 'react' import { Markdown } from '@tanstack/markdown/react' function ArticleLink(props: ComponentProps<'a'>) { return <a {...props} data-navigation="article" /> } export function Article() { return ( <Markdown components={{ a: ArticleLink }}> {'Read the [guide](/guide).'} </Markdown> ) } ``` The map is keyed by emitted tag names such as `a`, not AST discriminants such as `link`. Source: `docs/guides/react.md` ### HIGH Expecting HTML extension hooks in React Wrong: ```tsx import type { MarkdownExtension } from '@tanstack/markdown' import { Markdown } from '@tanstack/markdown/react' const paragraphHtml: MarkdownExtension = { name: 'paragraph-html', renderHtml(node) { return node.type === 'paragraph' ? '<aside>Rendered only by the HTML renderer</aside>' : undefined }, } export function Article() { return <Markdown extensions={[paragraphHtml]}>Ordinary content</Markdown> } ``` Correct: ```tsx import type { MarkdownExtension } from '@tanstack/markdown' import type { PropsWithChildren } from 'react' import { Markdown } from '@tanstack/markdown/react' const panelExtension: MarkdownExtension = { name: 'panel', transformDocument(document) { return { ...document, children: [ { type: 'component', name: 'panel', tagName: 'doc-panel', attributes: {}, children: document.children, }, ], } }, } function Panel({ children }: PropsWithChildren) { return <aside className="documentation-panel">{children}</aside> } export function Article() { return ( <Markdown components={{ 'doc-panel': Panel }} extensions={[panelExtension]} > Ordinary content </Markdown> ) } ``` `MarkdownExtension.renderHtml` is HTML-specific; portable custom output uses `ComponentNode` and an emitted-tag component mapping. Source: `docs/guides/extensions.md` ### CRITICAL Enabling raw HTML for untrusted input Wrong: ```tsx import { Markdown } from '@tanstack/markdown/react' export function UserPost({ source }: { source: string }) { return <Markdown allowHtml>{source}</Markdown> } ``` Correct: ```tsx import { Markdown } from '@tanstack/markdown/react' export function UserPost({ source }: { source: string }) { return <Markdown>{source}</Markdown> } ``` With `allowHtml`, React uses `dangerouslySetInnerHTML`; TanStack Markdown does not sanitize that raw HTML. Source: `docs/core-concepts/security.md` ### HIGH Tension: renderer parity versus React customization Core React SSR is tested against `renderHtml()`. React component replacements, raw HTML, highlighter output, and HTML-only extension hooks are application-controlled boundaries outside that parity guarantee. See also: [custom-extensions](../custom-extensions/SKILL.md) for portable `ComponentNode` output. ## Cross-References - [render-markdown](../render-markdown/SKILL.md) - shared `MarkdownInput`, parser options, AST behavior, and syntax profile. - [custom-extensions](../custom-extensions/SKILL.md) - emit custom tags that React can replace through `components`. - [production-pipelines](../production-pipelines/SKILL.md) - audit raw HTML, highlighter output, untrusted content, and SSR boundaries.
GitHub에서 보기