hast utility to transform to preact, react, solid, svelte, vue, etc
npm install hast-util-to-jsx-runtime[![Build][badge-build-image]][badge-build-url]
[![Coverage][badge-coverage-image]][badge-coverage-url]
[![Downloads][badge-downloads-image]][badge-downloads-url]
[![Size][badge-size-image]][badge-size-url]
hast utility to transform a tree to
preact, react, solid, svelte, vue, etcetera,
with an automatic JSX runtime.
* What is this?
* When should I use this?
* Install
* Use
* API
* toJsxRuntime(tree, options)
* Components
* CreateEvaluater
* ElementAttributeNameCase
* EvaluateExpression
* EvaluateProgram
* Evaluater
* ExtraProps
* Fragment
* Jsx
* JsxDev
* Options
* Props
* Source
* Space
* StylePropertyNameCase
* Errors
* Examples
* Example: Preact
* Example: Solid
* Example: Svelte
* Example: Vue
* Syntax
* Compatibility
* Security
* Related
* Contribute
* License
This package is a utility that takes a [hast][github-hast] tree and an
[automatic JSX runtime][reactjs-jsx-runtime] and turns the tree into anything
you wish.
You can use this package when you have a hast syntax tree and want to use it
with whatever framework.
This package uses an automatic JSX runtime,
which is a sort of lingua franca for frameworks to support JSX.
Notably,
automatic runtimes have support for passing extra information in development,
and have guaranteed support for fragments.
This package is [ESM only][github-gist-esm].
In Node.js (version 16+),
install with [npm][npmjs-install]:
``sh`
npm install hast-util-to-jsx-runtime
In Deno with [esm.sh][esmsh]:
`js`
import {toJsxRuntime} from 'https://esm.sh/hast-util-to-jsx-runtime@2'
In browsers with [esm.sh][esmsh]:
`html`
`js
import {h} from 'hastscript'
import {toJsxRuntime} from 'hast-util-to-jsx-runtime'
import {Fragment, jsxs, jsx} from 'react/jsx-runtime'
import {renderToStaticMarkup} from 'react-dom/server'
const tree = h('h1', 'Hello, world!')
const doc = renderToStaticMarkup(toJsxRuntime(tree, {Fragment, jsxs, jsx}))
console.log(doc)
`
Yields:
`html`Hello, world!
> Note:
> to add better type support,
> register a global JSX namespace:
>
> `ts`
> import type {JSX as Jsx} from 'react/jsx-runtime'
>
> declare global {
> namespace JSX {
> type ElementClass = Jsx.ElementClass
> type Element = Jsx.Element
> type IntrinsicElements = Jsx.IntrinsicElements
> }
> }
>
This package exports the identifier [toJsxRuntime][api-to-jsx-runtime].Components
It exports the [TypeScript][] types
[][api-components],CreateEvaluater
[][api-create-evaluater],ElementAttributeNameCase
[][api-element-attribute-name-case],EvaluateExpression
[][api-evaluate-expression],EvaluateProgram
[][api-evaluate-program],Evaluater
[][api-evaluater],ExtraProps
[][api-extra-props],Fragment
[][api-fragment],Jsx
[][api-jsx],JsxDev
[][api-jsx-dev],Options
[][api-options],Props
[][api-props],Source
[][api-source],Space
[][api-Space],StylePropertyNameCase
and
[][api-style-property-name-case].
There is no default export.
Transform a hast tree to
preact, react, solid, svelte, vue, etcetera,
with an automatic JSX runtime.
##### Parameters
* treeNode
([][github-hast-nodes])options
— tree to transform
* Options
([][api-options], required)
— configuration
##### Returns
Result from your configured JSX runtime
(JSX.Element if defined,unknown
otherwise which you can cast yourself).
Possible components to use (TypeScript type).
Each key is a tag name typed in JSX.IntrinsicElements,node
if defined.
Each value is either a different tag name
or a component accepting the corresponding props
(and an optional prop if passNode is on).
You can access props at JSX.IntrinsicElements.a
For example,
to find props for ,JSX.IntrinsicElements['a']
use .
###### Type
`ts
import type {Element} from 'hast'
type ExtraProps = {node?: Element | undefined}
type Components = {
[TagName in keyof JSX.IntrinsicElements]:
| Component
| keyof JSX.IntrinsicElements
}
type Component
// Class component:
| (new (props: ComponentProps) => JSX.ElementClass)
// Function component:
| ((props: ComponentProps) => JSX.Element | string | null | undefined)
`
Create an evaluator that turns ESTree ASTs from embedded MDX into values
(TypeScript type).
###### Parameters
There are no parameters.
###### Returns
Evaluater ([Evaluater][api-evaluater]).
Casing to use for attribute names (TypeScript type).
HTML casing is for example
class, stroke-linecap, xml:lang.className
React casing is for example, strokeLinecap, xmlLang.
###### Type
`ts`
type ElementAttributeNameCase = 'html' | 'react'
Turn an MDX expression into a value (TypeScript type).
###### Parameters
* expression (Expression from @types/estree)
— estree expression
###### Returns
Result of expression (unknown).
Turn an MDX program (export/import statements) into a value (TypeScript type).
###### Parameters
* program (Program from @types/estree)
— estree program
###### Returns
Result of program (unknown);undefined
should likely be as ESM changes the scope but doesn’t yield
something.
Evaluator that turns ESTree ASTs from embedded MDX into values (TypeScript
type).
###### Fields
* evaluateExpression ([EvaluateExpression][api-evaluate-expression])evaluateProgram
— evaluate an expression
* ([EvaluateProgram][api-evaluate-program])
— evaluate a program
Extra fields we pass (TypeScript type).
###### Type
`ts`
type ExtraProps = {node?: Element | undefined}
Represent the children,
typically a symbol (TypeScript type).
###### Type
`ts`
type Fragment = unknown
Create a production element (TypeScript type).
###### Parameters
* type (unknown)Fragment
— element type:
symbol,string
tag name (),props
component
* ([Props][api-props])children
— element props,
,node
and maybe key
* (string or undefined)
— dynamicly generated key to use
###### Returns
Element from your framework
(JSX.Element if defined,unknown
otherwise which you can cast yourself).
Create a development element (TypeScript type).
###### Parameters
* type (unknown)Fragment
— element type:
symbol,string
tag name (),props
component
* ([Props][api-props])children
— element props,
,node
and maybe key
* (string or undefined)isStaticChildren
— dynamicly generated key to use
* (boolean)jsxs
— whether two or more children are passed (in an array),
which is whether or jsx would be usedsource
* ([Source][api-source])self
— info about source
* (undefined)
— nothing (this is used by frameworks that have components,
we don’t)
###### Returns
Element from your framework
(JSX.Element if defined,unknown
otherwise which you can cast yourself).
Configuration (TypeScript type).
###### Fields
* Fragment ([Fragment][api-fragment], required)jsxDEV
— fragment
* ([JsxDev][api-jsx-dev], required in development)jsxs
— development JSX
* ([Jsx][api-jsx], required in production)jsx
— static JSX
* ([Jsx][api-jsx], required in production)components
— dynamic JSX
* ([Partial][api-components], optional)createEvaluater
— components to use
* ([CreateEvaluater][api-create-evaluater], optional)development
— create an evaluator that turns ESTree ASTs into values
* (boolean, default: false)jsxDEV
— whether to use when on or jsx and jsxs when offelementAttributeNameCase
* ElementAttributeNameCase
([][api-element-attribute-name-case],'react'
default: )filePath
— specify casing to use for attribute names
* (string, optional)jsxDEV
— file path to the original source file,
passed in source info to when using the automatic runtime withdevelopment: true
passNode
* (boolean, default: false)space
— pass the hast element node to components
* ([Space][api-space], default: 'html')tree
— whether is in the 'html' or 'svg' space, when an
Properties and children (TypeScript type).
###### Type
`ts
import type {Element} from 'hast'
type Props = {
[prop: string]:
| Array.style
| Record.node
| Element // For .`
| boolean
| number
| string
| undefined
children: Array
node?: Element | undefined
}
Info about source (TypeScript type).
###### Fields
* columnNumber (number or undefined)fileName
— column where thing starts (0-indexed)
* (string or undefined)lineNumber
— name of source file
* (number or undefined)
— line where thing starts (1-indexed)
Namespace (TypeScript type).
> 👉 Note:
> hast is not XML;
> it supports SVG as embedded in HTML;
> it does not support the features available in XML;
> passing SVG might break but fragments of modern SVG should be fine;
> use xast if you need to support SVG as XML.
###### Type
`ts`
type Space = 'html' | 'svg'
Casing to use for property names in style objects (TypeScript type).
CSS casing is for example background-color and -webkit-line-clamp.backgroundColor
DOM casing is for example and WebkitLineClamp.
###### Type
`ts`
type StylePropertyNameCase = 'css' | 'dom'
The following errors are thrown:
###### Expected Fragment in options
This error is thrown when either options is not passed at all oroptions.Fragment
when is undefined.
The automatic JSX runtime needs a symbol for a fragment to work.
To solve the error,
make sure you are passing the correct fragment symbol from your framework.
###### Expected jsxDEV in options when development: true
This error is thrown when options.development is turned on (true),options.jsxDEV
but when is not a function.
The automatic JSX runtime,
in development,
needs this function.
To solve the error,
make sure you are importing the correct runtime functions
(for example, 'react/jsx-dev-runtime'),jsxDEV
and pass .
###### Expected jsx in production options
###### Expected jsxs in production options
These errors are thrown when options.development is not turned onfalse
( or not defined),options.jsx
and when or options.jsxs are not functions.
The automatic JSX runtime,
in production,
needs these functions.
To solve the error,
make sure you are importing the correct runtime functions
(for example, 'react/jsx-runtime'),jsx
and pass and jsxs.
###### Cannot handle MDX estrees without createEvaluater
This error is thrown when MDX nodes are passed that represent JavaScript
programs or expressions.
Supporting JavaScript can be unsafe and requires a different project.
To support JavaScript,
pass a createEvaluater function in options.
###### Cannot parse style attribute
This error is thrown when a style attribute is found on an element,
which cannot be parsed as CSS.
Most frameworks don’t accept style as a string,style="color:red; /*"
so we need to parse it as CSS,
and pass it as an object.
But when broken CSS is used,
such as ,
we crash.
To solve the error,
make sure authors write valid CSS.
Alternatively,
pass options.ignoreInvalidStyle: true to swallow these errors.
> 👉 Note:
> you must set elementAttributeNameCase: 'html' for preact.
In Node.js,
do:
`js
import {h} from 'hastscript'
import {toJsxRuntime} from 'hast-util-to-jsx-runtime'
import {Fragment, jsx, jsxs} from 'preact/jsx-runtime'
import {render} from 'preact-render-to-string'
const result = render(
toJsxRuntime(h('h1', 'hi!'), {
Fragment,
jsx,
jsxs,
elementAttributeNameCase: 'html'
})
)
console.log(result)
`
Yields:
`html`hi!
In a browser,
do:
`js
import {h} from 'https://esm.sh/hastscript@9'
import {toJsxRuntime} from 'https://esm.sh/hast-util-to-jsx-runtime@2'
import {Fragment, jsx, jsxs} from 'https://esm.sh/preact@10/jsx-runtime'
import {render} from 'https://esm.sh/preact@10'
render(
toJsxRuntime(h('h1', 'hi!'), {
Fragment,
jsx,
jsxs,
elementAttributeNameCase: 'html'
}),
document.getElementById('root')
)
`
To add better type support,
register a global JSX namespace:
`ts
import type {JSX as Jsx} from 'preact/jsx-runtime'
declare global {
namespace JSX {
type ElementClass = Jsx.ElementClass
type Element = Jsx.Element
type IntrinsicElements = Jsx.IntrinsicElements
}
}
`
> 👉 Note:
> you must set elementAttributeNameCase: 'html' andstylePropertyNameCase: 'css'
> for Solid.
In Node.js,
do:
`js
import {h} from 'hastscript'
import {toJsxRuntime} from 'hast-util-to-jsx-runtime'
import {Fragment, jsx, jsxs} from 'solid-jsx/jsx-runtime'
console.log(
toJsxRuntime(h('h1', 'hi!'), {
Fragment,
jsx,
jsxs,
elementAttributeNameCase: 'html',
stylePropertyNameCase: 'css'
}).t
)
`
Yields:
`html`hi!
In a browser,
do:
`js
import {h} from 'https://esm.sh/hastscript@9'
import {toJsxRuntime} from 'https://esm.sh/hast-util-to-jsx-runtime@2'
import {Fragment, jsx, jsxs} from 'https://esm.sh/solid-js@1/h/jsx-runtime'
import {render} from 'https://esm.sh/solid-js@1/web'
render(Component, document.getElementById('root'))
function Component() {
return toJsxRuntime(h('h1', 'hi!'), {
Fragment,
jsx,
jsxs,
elementAttributeNameCase: 'html',
stylePropertyNameCase: 'css'
})
}
`
To add better type support,
register a global JSX namespace:
`ts
import type {JSX as Jsx} from 'solid-js/jsx-runtime'
declare global {
namespace JSX {
type ElementClass = Jsx.ElementClass
type Element = Jsx.Element
type IntrinsicElements = Jsx.IntrinsicElements
}
}
`
I have no clue how to render a Svelte component in Node,
but you can get that component with:
`js
import {h} from 'hastscript'
import {toJsxRuntime} from 'hast-util-to-jsx-runtime'
import {Fragment, jsx, jsxs} from 'svelte-jsx'
const svelteComponent = toJsxRuntime(h('h1', 'hi!'), {Fragment, jsx, jsxs})
console.log(svelteComponent)
`
Yields:
`text`
[class Component extends SvelteComponent]
Types for Svelte are broken.
Raise it with Svelte.
> 👉 Note:
> you must set elementAttributeNameCase: 'html' for Vue.
In Node.js,
do:
`jsvue@3.3
import serverRenderer from '@vue/server-renderer'
import {h} from 'hastscript'
import {toJsxRuntime} from 'hast-util-to-jsx-runtime'
import {Fragment, jsx, jsxs} from 'vue/jsx-runtime' // Available since .
console.log(
await serverRenderer.renderToString(
toJsxRuntime(h('h1', 'hi!'), {
Fragment,
jsx,
jsxs,
elementAttributeNameCase: 'html'
})
)
)
`
Yields:
`html`hi!
In a browser,
do:
`js
import {h} from 'https://esm.sh/hastscript@9'
import {toJsxRuntime} from 'https://esm.sh/hast-util-to-jsx-runtime@2'
import {createApp} from 'https://esm.sh/vue@3'
import {Fragment, jsx, jsxs} from 'https://esm.sh/vue@3/jsx-runtime'
createApp(Component).mount('#root')
function Component() {
return toJsxRuntime(h('h1', 'hi!'), {
Fragment,
jsx,
jsxs,
elementAttributeNameCase: 'html'
})
}
`
To add better type support,
register a global JSX namespace:
`ts
import type {JSX as Jsx} from 'vue/jsx-runtime'
declare global {
namespace JSX {
type ElementClass = Jsx.ElementClass
type Element = Jsx.Element
type IntrinsicElements = Jsx.IntrinsicElements
}
}
`
HTML is parsed according to WHATWG HTML (the living standard),
which is also followed by browsers such as Chrome,
Firefox,
and Safari.
Projects maintained by the unified collective are compatible with maintained
versions of Node.js.
When we cut a new major release,
we drop support for unmaintained versions of Node.
This means we try to keep the current release line,
hast-util-to-jsx-runtime@2,
compatible with Node.js 16.
Be careful with user input in your hast tree.
Use [hast-util-santize][github-hast-util-sanitize] to make hast trees safe.
* hastscript
— build hast trees
* hast-util-to-html
— serialize hast as HTML
* [hast-util-sanitize][github-hast-util-sanitize]
— sanitize hast
See [contributing.md][health-contributing]syntax-tree/.github
in
[][health]support.md`][health-support] for ways to get help.
for ways to get started.
See [
This project has a [code of conduct][health-coc].
By interacting with this repository,
organization,
or community you agree to abide by its terms.
[MIT][file-license] © [Titus Wormer][wooorm]
[api-components]: #components
[api-create-evaluater]: #createevaluater
[api-element-attribute-name-case]: #elementattributenamecase
[api-evaluate-expression]: #evaluateexpression
[api-evaluate-program]: #evaluateprogram
[api-evaluater]: #evaluater
[api-extra-props]: #extraprops
[api-fragment]: #fragment
[api-jsx]: #jsx
[api-jsx-dev]: #jsxdev
[api-options]: #options
[api-props]: #props
[api-source]: #source
[api-space]: #space
[api-style-property-name-case]: #stylepropertynamecase
[api-to-jsx-runtime]: #tojsxruntimetree-options
[badge-build-image]: https://github.com/syntax-tree/hast-util-to-jsx-runtime/workflows/main/badge.svg
[badge-build-url]: https://github.com/syntax-tree/hast-util-to-jsx-runtime/actions
[badge-coverage-image]: https://img.shields.io/codecov/c/github/syntax-tree/hast-util-to-jsx-runtime.svg
[badge-coverage-url]: https://codecov.io/github/syntax-tree/hast-util-to-jsx-runtime
[badge-downloads-image]: https://img.shields.io/npm/dm/hast-util-to-jsx-runtime.svg
[badge-downloads-url]: https://www.npmjs.com/package/hast-util-to-jsx-runtime
[badge-size-image]: https://img.shields.io/bundlejs/size/hast-util-to-jsx-runtime
[badge-size-url]: https://bundlejs.com/?q=hast-util-to-jsx-runtime
[esmsh]: https://esm.sh
[file-license]: license
[github-gist-esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
[github-hast]: https://github.com/syntax-tree/hast
[github-hast-nodes]: https://github.com/syntax-tree/hast#nodes
[github-hast-util-sanitize]: https://github.com/syntax-tree/hast-util-sanitize
[health]: https://github.com/syntax-tree/.github
[health-coc]: https://github.com/syntax-tree/.github/blob/main/code-of-conduct.md
[health-contributing]: https://github.com/syntax-tree/.github/blob/main/contributing.md
[health-support]: https://github.com/syntax-tree/.github/blob/main/support.md
[npmjs-install]: https://docs.npmjs.com/cli/install
[reactjs-jsx-runtime]: https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html
[typescript]: https://www.typescriptlang.org
[wooorm]: https://wooorm.com