1 | # rehype-react
|
2 |
|
3 | [![Build][build-badge]][build]
|
4 | [![Coverage][coverage-badge]][coverage]
|
5 | [![Downloads][downloads-badge]][downloads]
|
6 | [![Size][size-badge]][size]
|
7 | [![Sponsors][sponsors-badge]][collective]
|
8 | [![Backers][backers-badge]][collective]
|
9 | [![Chat][chat-badge]][chat]
|
10 |
|
11 | **[rehype][]** plugin to turn HTML into preact, react, solid, svelte, vue, etc.
|
12 |
|
13 | ## Contents
|
14 |
|
15 | * [What is this?](#what-is-this)
|
16 | * [When should I use this?](#when-should-i-use-this)
|
17 | * [Install](#install)
|
18 | * [Use](#use)
|
19 | * [API](#api)
|
20 | * [`unified().use(rehypeReact, options)`](#unifieduserehypereact-options)
|
21 | * [`Components`](#components)
|
22 | * [`Options`](#options)
|
23 | * [Types](#types)
|
24 | * [Compatibility](#compatibility)
|
25 | * [Security](#security)
|
26 | * [Related](#related)
|
27 | * [Contribute](#contribute)
|
28 | * [License](#license)
|
29 |
|
30 | ## What is this?
|
31 |
|
32 | This package is a [unified][] ([rehype][]) plugin that compiles HTML (hast) to
|
33 | any JSX runtime (preact, react, solid, svelte, vue, etc).
|
34 |
|
35 | **unified** is a project that transforms content with abstract syntax trees
|
36 | (ASTs).
|
37 | **rehype** adds support for HTML to unified.
|
38 | **hast** is the HTML AST that rehype uses.
|
39 | This is a rehype plugin that adds a compiler to compile hast to a JSX runtime.
|
40 |
|
41 | ## When should I use this?
|
42 |
|
43 | This plugin adds a compiler for rehype, which means that it turns the final
|
44 | HTML (hast) syntax tree into something else (in this case, a `JSX.Element`).
|
45 | It’s useful when you’re already using unified (whether remark or rehype) or are
|
46 | open to learning about ASTs (they’re powerful!) and want to render content in
|
47 | your app.
|
48 |
|
49 | If you’re not familiar with unified, then [`react-markdown`][react-markdown]
|
50 | might be a better fit.
|
51 | You can also use [`react-remark`][react-remark] instead, which is somewhere
|
52 | between `rehype-react` and `react-markdown`, as it does more that the former and
|
53 | is more modern (such as supporting hooks) than the latter, and also a good
|
54 | alternative.
|
55 | If you want to use JavaScript and JSX *inside* markdown files, use [MDX][].
|
56 |
|
57 | ## Install
|
58 |
|
59 | This package is [ESM only][esm].
|
60 | In Node.js (version 16+), install with [npm][]:
|
61 |
|
62 | ```sh
|
63 | npm install rehype-react
|
64 | ```
|
65 |
|
66 | In Deno with [`esm.sh`][esmsh]:
|
67 |
|
68 | ```js
|
69 | import rehypeReact from 'https://esm.sh/rehype-react@8'
|
70 | ```
|
71 |
|
72 | In browsers with [`esm.sh`][esmsh]:
|
73 |
|
74 | ```html
|
75 | <script type="module">
|
76 | import rehypeReact from 'https://esm.sh/rehype-react@8?bundle'
|
77 | </script>
|
78 | ```
|
79 |
|
80 | ## Use
|
81 |
|
82 | Say our React app `example.js` looks as follows:
|
83 |
|
84 | ```js
|
85 | import {Fragment, createElement, useEffect, useState} from 'react'
|
86 | import * as prod from 'react/jsx-runtime'
|
87 | import rehypeParse from 'rehype-parse'
|
88 | import rehypeReact from 'rehype-react'
|
89 | import {unified} from 'unified'
|
90 |
|
91 | // @ts-expect-error: the react types are missing.
|
92 | const production = {Fragment: prod.Fragment, jsx: prod.jsx, jsxs: prod.jsxs}
|
93 |
|
94 | const text = `<h2>Hello, world!</h2>
|
95 | <p>Welcome to my page 👀</p>`
|
96 |
|
97 | /**
|
98 | * @param {string} text
|
99 | * @returns {JSX.Element}
|
100 | */
|
101 | function useProcessor(text) {
|
102 | const [Content, setContent] = useState(createElement(Fragment))
|
103 |
|
104 | useEffect(
|
105 | function () {
|
106 | ;(async function () {
|
107 | const file = await unified()
|
108 | .use(rehypeParse, {fragment: true})
|
109 | .use(rehypeReact, production)
|
110 | .process(text)
|
111 |
|
112 | setContent(file.result)
|
113 | })()
|
114 | },
|
115 | [text]
|
116 | )
|
117 |
|
118 | return Content
|
119 | }
|
120 |
|
121 | export default function App() {
|
122 | return useProcessor(text)
|
123 | }
|
124 | ```
|
125 |
|
126 | …running that in Next.js or similar, we’d get:
|
127 |
|
128 | ```html
|
129 | <h2>Hello, world!</h2>
|
130 | <p>Welcome to my page 👀</p>
|
131 | ```
|
132 |
|
133 | ## API
|
134 |
|
135 | This package exports no identifiers.
|
136 | The default export is [`rehypeReact`][api-rehype-react].
|
137 |
|
138 | ### `unified().use(rehypeReact, options)`
|
139 |
|
140 | Turn HTML into preact, react, solid, svelte, vue, etc.
|
141 |
|
142 | ###### Parameters
|
143 |
|
144 | * `options` ([`Options`][api-options], required)
|
145 | — configuration
|
146 |
|
147 | ###### Returns
|
148 |
|
149 | Nothing (`undefined`).
|
150 |
|
151 | ###### Result
|
152 |
|
153 | This plugin registers a compiler that returns a `JSX.Element` where compilers
|
154 | typically return `string`.
|
155 | When using `.stringify` on `unified`, the result is such a `JSX.Element`.
|
156 | When using `.process` (or `.processSync`), the result is available at
|
157 | `file.result`.
|
158 |
|
159 | ###### Frameworks
|
160 |
|
161 | There are differences between what JSX frameworks accept, such as whether they
|
162 | accept `class` or `className`, or `background-color` or `backgroundColor`.
|
163 |
|
164 | For hast elements transformed by this project, this is be handled through
|
165 | options:
|
166 |
|
167 | | Framework | `elementAttributeNameCase` | `stylePropertyNameCase` |
|
168 | | --------- | -------------------------- | ----------------------- |
|
169 | | Preact | `'html'` | `'dom'` |
|
170 | | React | `'react'` | `'dom'` |
|
171 | | Solid | `'html'` | `'css'` |
|
172 | | Vue | `'html'` | `'dom'` |
|
173 |
|
174 | ### `Components`
|
175 |
|
176 | Possible components to use (TypeScript type).
|
177 |
|
178 | See [`Components` from
|
179 | `hast-util-to-jsx-runtime`](https://github.com/syntax-tree/hast-util-to-jsx-runtime#components)
|
180 | for more info.
|
181 |
|
182 | ### `Options`
|
183 |
|
184 | Configuration (TypeScript type).
|
185 |
|
186 | ###### Fields
|
187 |
|
188 | * `Fragment` ([`Fragment` from
|
189 | `hast-util-to-jsx-runtime`](https://github.com/syntax-tree/hast-util-to-jsx-runtime#fragment),
|
190 | required)
|
191 | — fragment
|
192 | * `jsx` ([`Jsx` from
|
193 | `hast-util-to-jsx-runtime`](https://github.com/syntax-tree/hast-util-to-jsx-runtime#jsx),
|
194 | required in production)
|
195 | — dynamic JSX
|
196 | * `jsxs` ([`Jsx` from
|
197 | `hast-util-to-jsx-runtime`](https://github.com/syntax-tree/hast-util-to-jsx-runtime#jsx),
|
198 | required in production)
|
199 | — static JSX
|
200 | * `jsxDEV` ([`JsxDev` from
|
201 | `hast-util-to-jsx-runtime`](https://github.com/syntax-tree/hast-util-to-jsx-runtime#jsxdev),
|
202 | required in development)
|
203 | — development JSX
|
204 | * `components` ([`Partial<Components>`][api-components], optional)
|
205 | — components to use
|
206 | * `development` (`boolean`, default: `false`)
|
207 | — whether to use `jsxDEV` when on or `jsx` and `jsxs` when off
|
208 | * `elementAttributeNameCase` (`'html'` or `'react'`, default: `'react'`)
|
209 | — specify casing to use for attribute names
|
210 | * `passNode` (`boolean`, default: `false`)
|
211 | — pass the hast element node to components
|
212 | * `space` (`'html'` or `'svg'`, default: `'html'`)
|
213 | — whether `tree` is in the `'html'` or `'svg'` space, when an `<svg>`
|
214 | element is found in the HTML space, this package already automatically
|
215 | switches to and from the SVG space when entering and exiting it
|
216 | * `stylePropertyNameCase`
|
217 | (`'css'` or `'dom'`, default: `'dom'`)
|
218 | — specify casing to use for property names in `style` objects
|
219 | * `tableCellAlignToStyle`
|
220 | (`boolean`, default: `true`)
|
221 | — turn obsolete `align` props on `td` and `th` into CSS `style` props
|
222 |
|
223 | ## Types
|
224 |
|
225 | This package is fully typed with [TypeScript][].
|
226 | It exports the additional types [`Components`][api-components] and
|
227 | [`Options`][api-options].
|
228 | More advanced types are exposed from
|
229 | [`hast-util-to-jsx-runtime`][hast-util-to-jsx-runtime].
|
230 |
|
231 | ## Compatibility
|
232 |
|
233 | Projects maintained by the unified collective are compatible with maintained
|
234 | versions of Node.js.
|
235 |
|
236 | When we cut a new major release, we drop support for unmaintained versions of
|
237 | Node.
|
238 | This means we try to keep the current release line, `rehype-react@^8`,
|
239 | compatible with Node.js 17.
|
240 |
|
241 | This plugin works with `rehype-parse` version 3+, `rehype` version 4+, and
|
242 | `unified` version 9+, and React 18+.
|
243 |
|
244 | ## Security
|
245 |
|
246 | Use of `rehype-react` can open you up to a [cross-site scripting (XSS)][xss]
|
247 | attack if the tree is unsafe.
|
248 | Use [`rehype-sanitize`][rehype-sanitize] to make the tree safe.
|
249 |
|
250 | ## Related
|
251 |
|
252 | * [`remark-rehype`](https://github.com/remarkjs/remark-rehype)
|
253 | — turn markdown into HTML to support rehype
|
254 | * [`rehype-remark`](https://github.com/rehypejs/rehype-remark)
|
255 | — turn HTML into markdown to support remark
|
256 | * [`rehype-retext`](https://github.com/rehypejs/rehype-retext)
|
257 | — rehype plugin to support retext
|
258 | * [`rehype-sanitize`][rehype-sanitize]
|
259 | — sanitize HTML
|
260 |
|
261 | ## Contribute
|
262 |
|
263 | See [`contributing.md`][contributing] in [`rehypejs/.github`][health] for ways
|
264 | to get started.
|
265 | See [`support.md`][support] for ways to get help.
|
266 |
|
267 | This project has a [code of conduct][coc].
|
268 | By interacting with this repository, organization, or community you agree to
|
269 | abide by its terms.
|
270 |
|
271 | ## License
|
272 |
|
273 | [MIT][license] © [Titus Wormer][titus], modified by [Tom MacWright][tom],
|
274 | [Mapbox][], and [rhysd][].
|
275 |
|
276 |
|
277 |
|
278 | [build-badge]: https://github.com/rehypejs/rehype-react/workflows/main/badge.svg
|
279 |
|
280 | [build]: https://github.com/rehypejs/rehype-react/actions
|
281 |
|
282 | [coverage-badge]: https://img.shields.io/codecov/c/github/rehypejs/rehype-react.svg
|
283 |
|
284 | [coverage]: https://codecov.io/github/rehypejs/rehype-react
|
285 |
|
286 | [downloads-badge]: https://img.shields.io/npm/dm/rehype-react.svg
|
287 |
|
288 | [downloads]: https://www.npmjs.com/package/rehype-react
|
289 |
|
290 | [size-badge]: https://img.shields.io/bundlejs/size/rehype-react
|
291 |
|
292 | [size]: https://bundlejs.com/?q=rehype-react
|
293 |
|
294 | [sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg
|
295 |
|
296 | [backers-badge]: https://opencollective.com/unified/backers/badge.svg
|
297 |
|
298 | [collective]: https://opencollective.com/unified
|
299 |
|
300 | [chat-badge]: https://img.shields.io/badge/chat-discussions-success.svg
|
301 |
|
302 | [chat]: https://github.com/rehypejs/rehype/discussions
|
303 |
|
304 | [npm]: https://docs.npmjs.com/cli/install
|
305 |
|
306 | [esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
|
307 |
|
308 | [esmsh]: https://esm.sh
|
309 |
|
310 | [health]: https://github.com/rehypejs/.github
|
311 |
|
312 | [contributing]: https://github.com/rehypejs/.github/blob/main/contributing.md
|
313 |
|
314 | [support]: https://github.com/rehypejs/.github/blob/main/support.md
|
315 |
|
316 | [coc]: https://github.com/rehypejs/.github/blob/main/code-of-conduct.md
|
317 |
|
318 | [license]: license
|
319 |
|
320 | [titus]: https://wooorm.com
|
321 |
|
322 | [tom]: https://macwright.org
|
323 |
|
324 | [mapbox]: https://www.mapbox.com
|
325 |
|
326 | [rhysd]: https://rhysd.github.io
|
327 |
|
328 | [hast-util-to-jsx-runtime]: https://github.com/syntax-tree/hast-util-to-jsx-runtime
|
329 |
|
330 | [mdx]: https://github.com/mdx-js/mdx/
|
331 |
|
332 | [react-markdown]: https://github.com/remarkjs/react-markdown
|
333 |
|
334 | [react-remark]: https://github.com/remarkjs/react-remark
|
335 |
|
336 | [rehype]: https://github.com/rehypejs/rehype
|
337 |
|
338 | [rehype-sanitize]: https://github.com/rehypejs/rehype-sanitize
|
339 |
|
340 | [typescript]: https://www.typescriptlang.org
|
341 |
|
342 | [unified]: https://github.com/unifiedjs/unified
|
343 |
|
344 | [xss]: https://en.wikipedia.org/wiki/Cross-site_scripting
|
345 |
|
346 | [api-components]: #components
|
347 |
|
348 | [api-options]: #options
|
349 |
|
350 | [api-rehype-react]: #unifieduserehypereact-options
|