JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 4050710
  • Score
    100M100P100Q238629F
  • License MIT

hast utility to transform to preact, react, solid, svelte, vue, etc

Package Exports

    Readme

    hast-util-to-jsx-runtime

    Build Coverage Downloads Size

    hast utility to transform a tree to preact, react, solid, svelte, vue, etcetera, with an automatic JSX runtime.

    Contents

    What is this?

    This package is a utility that takes a hast tree and an automatic JSX runtime and turns the tree into anything you wish.

    When should I use this?

    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.

    Install

    This package is ESM only. In Node.js (version 16+), install with npm:

    npm install hast-util-to-jsx-runtime

    In Deno with esm.sh:

    import {toJsxRuntime} from 'https://esm.sh/hast-util-to-jsx-runtime@2'

    In browsers with esm.sh:

    <script type="module">
      import {toJsxRuntime} from 'https://esm.sh/hast-util-to-jsx-runtime@2?bundle'
    </script>

    Use

    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:

    <h1>Hello, world!</h1>

    Note: to add better type support, register a global JSX namespace:

    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
      }
    }

    API

    This package exports the identifier toJsxRuntime. It exports the TypeScript types Components, CreateEvaluater, ElementAttributeNameCase, EvaluateExpression, EvaluateProgram, Evaluater, ExtraProps, Fragment, Jsx, JsxDev, Options, Props, Source, Space, and StylePropertyNameCase. There is no default export.

    toJsxRuntime(tree, options)

    Transform a hast tree to preact, react, solid, svelte, vue, etcetera, with an automatic JSX runtime.

    Parameters
    • tree (Node) — tree to transform
    • options (Options, required) — configuration
    Returns

    Result from your configured JSX runtime (JSX.Element if defined, otherwise unknown which you can cast yourself).

    Components

    Possible components to use (TypeScript type).

    Each key is a tag name typed in JSX.IntrinsicElements, if defined. Each value is either a different tag name or a component accepting the corresponding props (and an optional node prop if passNode is on).

    You can access props at JSX.IntrinsicElements. For example, to find props for a, use JSX.IntrinsicElements['a'].

    Type
    import type {Element} from 'hast'
    
    type ExtraProps = {node?: Element | undefined}
    
    type Components = {
      [TagName in keyof JSX.IntrinsicElements]:
        | Component<JSX.IntrinsicElements[TagName] & ExtraProps>
        | keyof JSX.IntrinsicElements
    }
    
    type Component<ComponentProps> =
      // Class component:
      | (new (props: ComponentProps) => JSX.ElementClass)
      // Function component:
      | ((props: ComponentProps) => JSX.Element | string | null | undefined)

    CreateEvaluater

    Create an evaluator that turns ESTree ASTs from embedded MDX into values (TypeScript type).

    Parameters

    There are no parameters.

    Returns

    Evaluater (Evaluater).

    ElementAttributeNameCase

    Casing to use for attribute names (TypeScript type).

    HTML casing is for example class, stroke-linecap, xml:lang. React casing is for example className, strokeLinecap, xmlLang.

    Type
    type ElementAttributeNameCase = 'html' | 'react'

    EvaluateExpression

    Turn an MDX expression into a value (TypeScript type).

    Parameters
    • expression (Expression from @types/estree) — estree expression
    Returns

    Result of expression (unknown).

    EvaluateProgram

    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); should likely be undefined as ESM changes the scope but doesn’t yield something.

    Evaluater

    Evaluator that turns ESTree ASTs from embedded MDX into values (TypeScript type).

    Fields

    ExtraProps

    Extra fields we pass (TypeScript type).

    Type
    type ExtraProps = {node?: Element | undefined}

    Fragment

    Represent the children, typically a symbol (TypeScript type).

    Type
    type Fragment = unknown

    Jsx

    Create a production element (TypeScript type).

    Parameters
    • type (unknown) — element type: Fragment symbol, tag name (string), component
    • props (Props) — element props, children, and maybe node
    • key (string or undefined) — dynamicly generated key to use
    Returns

    Element from your framework (JSX.Element if defined, otherwise unknown which you can cast yourself).

    JsxDev

    Create a development element (TypeScript type).

    Parameters
    • type (unknown) — element type: Fragment symbol, tag name (string), component
    • props (Props) — element props, children, and maybe node
    • key (string or undefined) — dynamicly generated key to use
    • isStaticChildren (boolean) — whether two or more children are passed (in an array), which is whether jsxs or jsx would be used
    • source (Source) — info about source
    • self (undefined) — nothing (this is used by frameworks that have components, we don’t)
    Returns

    Element from your framework (JSX.Element if defined, otherwise unknown which you can cast yourself).

    Options

    Configuration (TypeScript type).

    Fields
    • Fragment (Fragment, required) — fragment
    • jsxDEV (JsxDev, required in development) — development JSX
    • jsxs (Jsx, required in production) — static JSX
    • jsx (Jsx, required in production) — dynamic JSX
    • components (Partial<Components>, optional) — components to use
    • createEvaluater (CreateEvaluater, optional) — create an evaluator that turns ESTree ASTs into values
    • development (boolean, default: false) — whether to use jsxDEV when on or jsx and jsxs when off
    • elementAttributeNameCase (ElementAttributeNameCase, default: 'react') — specify casing to use for attribute names
    • filePath (string, optional) — file path to the original source file, passed in source info to jsxDEV when using the automatic runtime with development: true
    • passNode (boolean, default: false) — pass the hast element node to components
    • space (Space, default: 'html') — whether tree is in the 'html' or 'svg' space, when an <svg> element is found in the HTML space, this package already automatically switches to and from the SVG space when entering and exiting it
    • stylePropertyNameCase (StylePropertyNameCase, default: 'dom') — specify casing to use for property names in style objects
    • tableCellAlignToStyle (boolean, default: true) — turn obsolete align props on td and th into CSS style props

    Props

    Properties and children (TypeScript type).

    Type
    import type {Element} from 'hast'
    
    type Props = {
      [prop: string]:
        | Array<JSX.Element | string | null | undefined> // For `children`.
        | Record<string, string> // For `style`.
        | Element // For `node`.
        | boolean
        | number
        | string
        | undefined
      children: Array<JSX.Element | string | null | undefined> | undefined
      node?: Element | undefined
    }

    Source

    Info about source (TypeScript type).

    Fields
    • columnNumber (number or undefined) — column where thing starts (0-indexed)
    • fileName (string or undefined) — name of source file
    • lineNumber (number or undefined) — line where thing starts (1-indexed)

    Space

    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
    type Space = 'html' | 'svg'

    StylePropertyNameCase

    Casing to use for property names in style objects (TypeScript type).

    CSS casing is for example background-color and -webkit-line-clamp. DOM casing is for example backgroundColor and WebkitLineClamp.

    Type
    type StylePropertyNameCase = 'css' | 'dom'

    Errors

    The following errors are thrown:

    Expected `Fragment` in options

    This error is thrown when either options is not passed at all or when options.Fragment 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), but when options.jsxDEV 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'), and pass jsxDEV.

    Expected `jsx` in production options
    Expected `jsxs` in production options

    These errors are thrown when options.development is not turned on (false or not defined), and when options.jsx 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'), and pass jsx 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, so we need to parse it as CSS, and pass it as an object. But when broken CSS is used, such as style="color:red; /*", we crash.

    To solve the error, make sure authors write valid CSS. Alternatively, pass options.ignoreInvalidStyle: true to swallow these errors.

    Examples

    Example: Preact

    👉 Note: you must set elementAttributeNameCase: 'html' for preact.

    In Node.js, do:

    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:

    <h1>hi!</h1>

    In a browser, do:

    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:

    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
      }
    }

    Example: Solid

    👉 Note: you must set elementAttributeNameCase: 'html' and stylePropertyNameCase: 'css' for Solid.

    In Node.js, do:

    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:

    <h1 >hi!</h1>

    In a browser, do:

    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:

    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
      }
    }

    Example: Svelte

    I have no clue how to render a Svelte component in Node, but you can get that component with:

    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:

    [class Component extends SvelteComponent]

    Types for Svelte are broken. Raise it with Svelte.

    Example: Vue

    👉 Note: you must set elementAttributeNameCase: 'html' for Vue.

    In Node.js, do:

    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 `vue@3.3`.
    
    console.log(
      await serverRenderer.renderToString(
        toJsxRuntime(h('h1', 'hi!'), {
          Fragment,
          jsx,
          jsxs,
          elementAttributeNameCase: 'html'
        })
      )
    )

    Yields:

    <h1>hi!</h1>

    In a browser, do:

    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:

    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
      }
    }

    Syntax

    HTML is parsed according to WHATWG HTML (the living standard), which is also followed by browsers such as Chrome, Firefox, and Safari.

    Compatibility

    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.

    Security

    Be careful with user input in your hast tree. Use hast-util-santize to make hast trees safe.

    Contribute

    See contributing.md in syntax-tree/.github for ways to get started. See support.md for ways to get help.

    This project has a code of conduct. By interacting with this repository, organization, or community you agree to abide by its terms.

    License

    MIT © Titus Wormer