HAST to JSX Runtime Transformer
hast-util-to-jsx-runtime is a utility within the unifiedjs ecosystem that transforms a HAST (Hypertext Abstract Syntax Tree) into a representation suitable for automatic JSX runtimes (React, Preact, Solid, Svelte, Vue, etc.). It acts as a bridge, allowing HTML-like content represented as HAST nodes to be rendered efficiently by various JSX-based frameworks without direct framework-specific code. The package is currently at version 2.3.6 and follows a release cadence driven by feature additions, bug fixes, and type improvements, typically releasing patch and minor versions regularly. Its core value proposition is enabling framework-agnostic rendering of parsed HTML, leveraging the standard automatic JSX runtime API for broad compatibility. This design choice differentiates it by providing a unified approach to content rendering across different JSX environments.
Common errors
-
TS2304: Cannot find name 'JSX'.
cause The global `JSX` namespace required by TypeScript for JSX elements is not defined or is not correctly scoped.fixAdd the following to a global declaration file (e.g., `src/global.d.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; } }` (adjust `react/jsx-runtime` for your framework). -
Error [ERR_REQUIRE_ESM]: require() of ES Module ... hast-util-to-jsx-runtime.js not supported.
cause Attempting to use CommonJS `require()` to import an ESM-only package.fixConvert your consuming file or project to use ES Modules. Use `import { toJsxRuntime } from 'hast-util-to-jsx-runtime'` and ensure your `package.json` contains `"type": "module"` or files use the `.mjs` extension. -
TypeError: (0 , jsx_runtime_1.jsxs) is not a function
cause The JSX runtime functions (e.g., `jsx`, `jsxs`, `Fragment`) are not being correctly imported or passed to `toJsxRuntime`.fixEnsure you are importing the correct runtime functions from your framework (e.g., `import { Fragment, jsxs, jsx } from 'react/jsx-runtime'`) and correctly passing them in the `options` object: `toJsxRuntime(tree, { Fragment, jsxs, jsx })`.
Warnings
- breaking The `hast-util-to-jsx-runtime` package is ESM-only (ECMAScript Modules) since version 2.0.0. Attempting to import it using CommonJS `require()` syntax will result in an `ERR_REQUIRE_ESM` error.
- gotcha When using TypeScript, if the global `JSX` namespace is not correctly defined or augmented, you may encounter type errors related to `JSX.Element`, `JSX.IntrinsicElements`, or `JSX.ElementClass`.
- gotcha The package processes `hast` trees into JSX. For actual client-side interactivity, simply generating JSX elements is not enough. You will need to hydrate or mount the resulting JSX with your chosen framework on the client side.
Install
-
npm install hast-util-to-jsx-runtime -
yarn add hast-util-to-jsx-runtime -
pnpm add hast-util-to-jsx-runtime
Imports
- toJsxRuntime
const { toJsxRuntime } = require('hast-util-to-jsx-runtime')import { toJsxRuntime } from 'hast-util-to-jsx-runtime' - Options
import type { Options } from 'hast-util-to-jsx-runtime' - JSX namespace
declare global { namespace JSX { /* ... */ } }
Quickstart
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';
// Create a simple HAST tree
const tree = h('div', { className: 'container' }, [
h('h1', 'Hello, world!'),
h('p', 'This is a paragraph rendered from a HAST tree.'),
h('button', { onClick: 'alert("Clicked!")' }, 'Click Me')
]);
// Transform the HAST tree into JSX elements using React's automatic runtime
// Note: `onClick` is a string here, for actual interactivity in the browser,
// you would typically handle event listeners differently or use a client-side hydration.
const jsxResult = toJsxRuntime(tree, { Fragment, jsxs, jsx });
// Render the JSX elements to a static HTML string using React DOM server renderer
const doc = renderToStaticMarkup(jsxResult);
console.log(doc);
// Expected output:
// <div class="container"><h1>Hello, world!</h1><p>This is a paragraph rendered from a HAST tree.</p><button onclick="alert("Clicked!")">Click Me</button></div>