---
name: react-markdown
description: Use react-markdown ^10.0.0 correctly as an ESM-only React 18+ component, including synchronous, asynchronous, plugin, filtering, URL, and migration guidance.
---
Verified against react-markdown@10.1.0 on 2026-09-08. 3 of 3 examples executed.
# react-markdown
## Version and runtime
This skill targets `react-markdown` `^10.0.0`, meaning the 10.x release line.
- The package is ESM-only.
- Node.js 16+ and React 18+ are required.
- The default export is `Markdown`.
- Named exports include `MarkdownAsync`, `MarkdownHooks`, and `defaultUrlTransform`.
- Type exports include `AllowElement`, `Components`, `ExtraProps`, `HooksOptions`, `Options`, and `UrlTransform`.
Import it with ESM syntax:
```ts pmcp-example
import assert from 'node:assert/strict'
import React from 'react'
import Markdown, {defaultUrlTransform} from 'react-markdown'
const element = Markdown({children: '# Hello'})
assert.equal(React.isValidElement(element), true)
assert.equal(typeof defaultUrlTransform, 'function')
```
`react-markdown` is a React component, not a standalone Markdown-to-string converter. In an application, render it through React, for example with `createRoot(...).render(...)`. A direct script can still call the component function and inspect that it produces a React element, as in the example above; it does not produce HTML text.
## Basic rendering
Pass Markdown as the `children` option:
```tsx
{'# Hi, *Pluto*!'}
```
The documented component signature is `Markdown(options: Options): ReactElement`.
## Options and plugins
`Options` includes:
- `children`
- `components`
- `remarkPlugins`
- `rehypePlugins`
- `allowedElements`
- `disallowedElements`
- `skipHtml`
- `unwrapDisallowed`
- `remarkRehypeOptions`
- `urlTransform`
Plugins are supplied as React props. GitHub-Flavored Markdown is not built in; add `remark-gfm` through `remarkPlugins` when needed:
```tsx
import Markdown from 'react-markdown'
import remarkGfm from 'remark-gfm'
{'Just a link: www.nasa.gov.'}
```
`components` maps rendered element names to another tag or to a component. For example, an `h1` can be rendered as `h2`, and an `em` renderer receives props including `node`:
```tsx
}
}}
/>
```
Raw HTML requires the separate `rehype-raw` plugin and a trusted environment. Without that plugin, HTML is escaped or ignored when `skipHtml` is enabled.
## URL handling
The package exports `defaultUrlTransform(url: string): string`. Pass a custom URL transform with the `urlTransform` option when URL handling needs to differ from the default.
```ts pmcp-example
import assert from 'node:assert/strict'
import {defaultUrlTransform} from 'react-markdown'
assert.equal(typeof defaultUrlTransform, 'function')
assert.equal(typeof defaultUrlTransform('https://example.com'), 'string')
```
## Asynchronous processing
Use `MarkdownAsync` when remark or rehype processing is asynchronous. Its signature is `MarkdownAsync(options: Options): Promise`.
```ts pmcp-example
import assert from 'node:assert/strict'
import React from 'react'
import {MarkdownAsync} from 'react-markdown'
const element = await MarkdownAsync({children: '# Hi'})
assert.equal(React.isValidElement(element), true)
```
The package also documents a subpath import:
```ts
import MarkdownAsync from 'react-markdown/async'
const result = await MarkdownAsync({children: '# Hi'})
```
`MarkdownAsync` supports async plugins through `async`/`await`. Components returning promises are supported on the server.
For client-side async support, use `MarkdownHooks`. It uses `useEffect` and `useState`, runs on the client, and does not immediately render processed content. Its `fallback` option is shown while processing:
```tsx
import {MarkdownHooks} from 'react-markdown'
Loading…
} remarkPlugins={[asyncPlugin]}>
{markdown}
```
`fallback` belongs to `HooksOptions` and `MarkdownHooks`; it is not an option for regular `Markdown`.
A direct `bun example.ts` script is not a React renderer, so it cannot exercise `MarkdownHooks`' client hook lifecycle. Render it inside a React application instead.
## v10 migration mistakes
### Do not pass `className` to `Markdown`
Version 10 removed the `className` prop. Wrap the component explicitly instead:
```tsx
{markdown}
```
This also lets the caller choose the wrapper tag and its other props.
### Do not use pre-v9 URL transform names
Older examples may use `transformImageUri` or `transformLinkUri`. Those were replaced by the single `urlTransform` option.
### Do not assume the old package/runtime shape
Older code may assume CommonJS, older Node or React minimums, or imports that do not follow the package's newer exports. Version 10 is ESM-only, targets Node.js 16+, and requires React 18+ and `@types/react` 18+.
## What this skill does not cover
- The detailed behavior of individual Markdown constructs or URL transformations.
- The API or configuration of third-party plugins such as `remark-gfm` or `rehype-raw`.
- Authoring async remark or rehype plugins.
- React DOM setup, server rendering setup, or client hook lifecycle execution.
- The exact React element tree or generated HTML after a renderer processes the returned element.