React-komponent der renderer Markdown som React-elementer, med remark/rehype-plugins og syntaksfremhævning.
@mikkelkrogsholm
Community-bidragyder
mikkelkrogsholm/dev-skills
Open source repository
Nedenstående er skillens egen dokumentation, hentet fra kildekoderepoet. Ophavsret tilhører forfatteren.
CRITICAL: Your training data for react-markdown is unreliable. APIs change between versions and memorized patterns may be wrong or deprecated. Before writing any code, you MUST use
WebFetchto read the current README:
WebFetch("https://github.com/remarkjs/react-markdown")If you need a specific remark or rehype plugin, also fetch:
WebFetch("https://github.com/remarkjs/remark/blob/main/doc/plugins.md")WebFetch("https://github.com/rehypejs/rehype/blob/main/doc/plugins.md")Do not proceed without fetching first. Never assume prop names or plugin options — verify against current docs.
react-markdown renders Markdown as React elements using a plugin pipeline: Markdown → remark (AST) → rehype (HTML AST) → React components. No dangerouslySetInnerHTML — everything is React elements.
dangerouslySetInnerHTML — outputs React elementsremark-gfmrehype-highlight or rehype-pretty-codeThe base package renders standard Markdown. For most apps you need two plugins:
import Markdown from 'react-markdown'
import remarkGfm from 'remark-gfm'
import rehypeHighlight from 'rehype-highlight'
<Markdown
remarkPlugins={[remarkGfm]}
rehypePlugins={[rehypeHighlight]}
>
{markdownContent}
</Markdown>
Packages to install: bun add react-markdown remark-gfm rehype-highlight
Don't forget the highlight.js CSS theme for syntax highlighting:
import 'highlight.js/styles/github-dark.css'
Override any HTML element rendered by Markdown. This is how you add custom styling, clickable links, or interactive elements:
<Markdown
components={{
// Custom code blocks
code({ className, children, ...props }) {
const match = /language-(\w+)/.exec(className || '')
return match ? (
<pre className="code-block">
<code className={className} {...props}>{children}</code>
</pre>
) : (
<code className="inline-code" {...props}>{children}</code>
)
},
// Custom links — open external in new tab
a({ href, children, ...props }) {
const isExternal = href?.startsWith('http')
return (
<a href={href} target={isExternal ? '_blank' : undefined} rel={isExternal ? 'noopener noreferrer' : undefined} {...props}>
{children}
</a>
)
},
// Custom images
img({ src, alt, ...props }) {
return <img src={src} alt={alt} loading="lazy" {...props} />
},
}}
>
{content}
</Markdown>
Always include remark-gfm for user-facing Markdown. Without it, tables, strikethrough, autolinks, and task lists silently render as plain text. This is the most common "bug" reported by users — the Markdown looks broken because GFM isn't enabled by default.
The children prop must be a string. Passing JSX or a React element to <Markdown> will not work. If your content is in a variable, ensure it's a string type: <Markdown>{String(content)}</Markdown>.
Distinguish inline code from code blocks in component overrides. The code component receives both inline (code) and block (```) code. Check for the presence of className (which contains language-* for fenced blocks) to differentiate. Inline code has no className.
Plugin order matters. remark plugins run in array order on the Markdown AST, then rehype plugins run on the HTML AST. If a rehype plugin depends on structure created by a remark plugin, ordering is critical. remarkGfm should always come first in remarkPlugins.
Re-renders on every content change. react-markdown parses and re-renders the full Markdown tree whenever the children string changes. For streaming chat (character-by-character updates), this can be expensive. Consider debouncing updates or using React.memo with a custom comparison on the parent component.