# react-markdown-to-html
**Repository Path**: mirrors_svenanders/react-markdown-to-html
## Basic Information
- **Project Name**: react-markdown-to-html
- **Description**: React Component that converts a Markdown file to HTML
- **Primary Language**: Unknown
- **License**: ISC
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-08-18
- **Last Updated**: 2026-09-05
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# react-markdown-remote
[](https://www.npmjs.com/package/react-markdown-remote)
[](https://www.npmjs.com/package/react-markdown-remote)
[](./LICENSE)
**Point `src` at a markdown file. Relative images and links actually work.**
`react-markdown` takes a string. This package takes a **URL**. It fetches the file, rewrites `./shot.png` and `./api.md` against that file — not against the page you dropped the component on — and renders React elements. GitHub blob URLs, GitLab files, gists, and any `http(s)` markdown document.
No `dangerouslySetInnerHTML`. No jQuery. GitHub-flavored markdown is on by default.
Using an LLM or coding agent? Copy the [agent spec](#for-llms) into the prompt.
```bash
npm install react-markdown-remote
```
```tsx
import { RemoteMarkdown } from "react-markdown-remote";
import "react-markdown-remote/styles.css"; // optional typography
```
Peer: `react >= 18`. Dual ESM/CJS. `"use client"` for Next.js App Router.
[npm](https://www.npmjs.com/package/react-markdown-remote) · [GitHub](https://github.com/robbestad/react-markdown-remote)
## The problem this solves
Drop a README into a React app and the pictures die.
```md

[API](./api.md)
```
On GitHub those paths are relative to the **markdown file**. In your app the browser resolves them against the current page, so they 404. Blob URLs cannot be used as `img src` either — images need `raw.githubusercontent.com`, links need `github.com/.../blob/...`.
That glue is the whole product. Parsing is [`react-markdown`](https://github.com/remarkjs/react-markdown). Fetch + rewrite is this package.
| You have | Use |
| --- | --- |
| A markdown string already in memory | `react-markdown` |
| A **file at a URL**, with `./` images and links | **react-markdown-remote** |
| JSX inside markdown | MDX |
## What `src` accepts
| `src` | Fetches | `./shot.png` becomes |
| --- | --- | --- |
| `https://github.com/org/repo/blob/main/docs/guide.md` | raw GitHub | raw image under `docs/` |
| `https://github.com/org/repo` | `README.md` on `HEAD` | raw image at repo root |
| `https://github.com/org/repo/tree/main/docs` | `docs/README.md` | raw image under `docs/` |
| `https://gitlab.com/group/app/-/blob/main/README.md` | GitLab `/-/raw/` | GitLab raw image |
| `https://gist.github.com/user/id` | gist raw | gist raw |
| `https://example.com/docs/guide.md` | that URL | `https://example.com/docs/shot.png` |
| `/docs/README.md` | same origin | same-origin, relative to the file |
On GitHub and GitLab, `/root.png` is the **repo root**, matching how those hosts render READMEs. On a generic URL it is the host root.
Slash-branches: `.../blob/refs/heads/feature/foo/README.md`.
## Rewrite, without the component
```ts
import { resolveDocument, rewriteUrl } from "react-markdown-remote";
const doc = resolveDocument("https://github.com/acme/app/blob/main/docs/guide.md");
rewriteUrl("./shot.png", doc, "image");
// https://raw.githubusercontent.com/acme/app/main/docs/shot.png
rewriteUrl("./extra.md", doc, "link");
// https://github.com/acme/app/blob/main/docs/extra.md
```
`javascript:`, `data:`, `vbscript:`, and `file:` are dropped. Absolute `http(s)` links stay. GitHub **blob** URLs used as images become raw.
Need the string on the server? `await loadMarkdown(src)` returns `{ markdown, document }`.
## API
```tsx
Loading…
}
error={(err) => {err.message}
}
onLoad={({ markdown, document }) => console.log(document.fetchUrl)}
components={{ a: (props) => }}
/>
```
| Prop | Type | Default | Notes |
| --- | --- | --- | --- |
| `src` | `string` | required | Document URL |
| `fetch` | `typeof fetch` | `globalThis.fetch` | Proxy for hosts without CORS. **Keep `src` as the real document URL** |
| `requestInit` | `RequestInit` | — | Merged in; `signal` is owned by the component |
| `gfm` | `boolean` | `true` | `remark-gfm` (tables, task lists, strikethrough) |
| `loading` | `ReactNode` | status text | `null` hides it |
| `error` | `ReactNode` \| `(Error) => ReactNode` | alert with the message | `null` hides it |
| `onLoad` | `(result) => void` | — | Markdown + resolved document |
| `onError` | `(Error) => void` | — | Not called for aborted fetches |
| `origin` | `string` | `window.location.href` | Base for relative `src` |
Every [`react-markdown`](https://github.com/remarkjs/react-markdown) option except `children` is forwarded (`components`, `remarkPlugins`, `rehypePlugins`, `urlTransform`, …). Your `urlTransform` runs **after** the relative rewrite; `defaultUrlTransform` sanitizes last.
```ts
import {
RemoteMarkdown,
useRemoteMarkdown,
loadMarkdown,
resolveDocument,
rewriteUrl,
} from "react-markdown-remote";
```
## CORS and XSS
`raw.githubusercontent.com` sends `Access-Control-Allow-Origin: *`. Many other hosts do not. If the browser blocks the request, pass a `fetch` that hits **your** proxy, and leave `src` pointing at the real file so rewrite still has the right base.
Untrusted markdown is safe by default: no `dangerouslySetInnerHTML`, no raw HTML parsing. Do not add `rehype-raw` unless you sanitize.
## Demo
```bash
npm install
npm run demo
```
Local fixture (relative image + link) and a live GitHub README preset.
## Migration from `react-markdown-to-html`
That 2015 package dumped `marked` through `innerHTML`. It is deprecated on npm. This is the replacement.
```diff
- import Markdown2HTML from "react-markdown-to-html"
-
+ import { RemoteMarkdown } from "react-markdown-remote"
+
```
React 18+ is required. jQuery, lodash, and `marked` are gone. A bare `README.md` only works if that file is served from the current origin.
## For LLMs
Copy everything in the block below into an LLM or coding-agent prompt when you want it to use `react-markdown-remote`.
```
Use react-markdown-remote v2 to fetch a markdown FILE from a URL and render it in React 18+.
Install: npm install react-markdown-remote
Import: import { RemoteMarkdown } from "react-markdown-remote"
Optional CSS: import "react-markdown-remote/styles.css"
Peer: react >= 18. Dual ESM/CJS. The published bundle starts with "use client".
Default export is the same component.
This is NOT a markdown parser you pass a string to. react-markdown already does that.
This package's job is: fetch src + rewrite relative images/links against THAT file.
API:
ReactNode) // default alert; null to hide
onLoad?: (result: { markdown: string, document: ResolvedDocument }) => void
onError?: (err: Error) => void // not called on abort
className?: string
style?: CSSProperties
id?: string
...reactMarkdownOptions // components, remarkPlugins, rehypePlugins, urlTransform, …
/>
// Headless:
useRemoteMarkdown(src, { fetch, requestInit, origin })
-> { status: "loading" }
| { status: "ready", markdown, document }
| { status: "error", error: Error }
await loadMarkdown(src, { fetch, requestInit, signal, origin })
-> { markdown, document }
resolveDocument(src, origin?) -> ResolvedDocument
rewriteUrl(url, document, "image" | "link") -> string
src mapping:
- github.com/org/repo/blob/ref/path.md -> fetch raw.githubusercontent.com/.../path.md
images: raw under the file's directory
links: github.com/.../blob/... under the file's directory
- github.com/org/repo -> README.md on HEAD
- github.com/org/repo/tree/ref/dir -> dir/README.md
- gitlab.com/group/app/-/blob/ref/file -> /-/raw/ for fetch and images, /-/blob/ for links
- gist.github.com/user/id -> gist.githubusercontent.com/user/id/raw
- https://example.com/docs/guide.md -> that URL; relatives against /docs/
- /docs/README.md -> same origin (needs a browser origin or origin option)
- Slash branches: .../blob/refs/heads/feature/foo/README.md
- On GitHub/GitLab, /foo.png is REPO root. On generic URLs, /foo.png is HOST root.
Rules:
- Do NOT use dangerouslySetInnerHTML. Do NOT add rehype-raw unless the caller sanitizes.
- Do NOT pass the markdown string as children. Pass src.
- If you proxy fetch, src must still be the original GitHub/GitLab/file URL so rewrite works.
- javascript:, data:, vbscript:, file: URLs are stripped. Leave that alone.
- User urlTransform runs AFTER rewrite; defaultUrlTransform sanitizes last.
- Do not fetch on every render. The component aborts in-flight work when src changes.
- Successor to the deprecated package react-markdown-to-html (jQuery + marked + innerHTML). Never revive that API.
Minimal:
import { RemoteMarkdown } from "react-markdown-remote"
export function Readme() {
return
}
```
## License
ISC