All questions

JSX Runtime

Premium

JSX Runtime

JSX isn't magic — it's syntax sugar that a compiler rewrites into plain function calls. The modern "automatic runtime" (React 17+, and what Babel/SWC emit by default) compiles <div id="a">hi</div> into jsx('div', { id: 'a', children: 'hi' }). Implementing jsx (and its siblings jsxs and Fragment) shows you exactly what your markup becomes: a plain object describing type, props, and a key.

Implement jsx(type, props, key), jsxs (its alias for static-array children), and a Fragment symbol. Return a vnode { type, key, props } — with children living inside props.children, and key pulled out as a separate field.

Signature

function jsx(type, props, key) {
  // returns { type, key, props }  (props.children holds the children)
}

Examples

// <a href="/x">go</a>   compiles to:
jsx('a', { href: '/x', children: 'go' });
// -> { type: 'a', key: null, props: { href: '/x', children: 'go' } }

// <li key="row-1">x</li> compiles to:
jsx('li', { children: 'x' }, 'row-1'); // key is the 3rd arg

Notes

  • Children go in props — unlike classic createElement(type, props, ...children), the automatic runtime puts children inside props.children. Don't pull them out.
  • key is a separate arg — the transform passes key as the third argument, not in props; store it as element.key (stringified), and keep it out of props.
  • jsxs === jsx — the transform calls jsxs when the children are a static array (an optimization hint); behavior is identical.
  • Fragment — a unique symbol used as the type for <>…</>; a renderer treats it as "just my children, no wrapper element".

Unlock the solution & editor

  • Runnable editor + tests

    Solve in the browser with instant Jest feedback.

  • Detailed solutions

    Walkthroughs, edge cases, and complexity notes.

  • Multi-framework variants

    React, Vue, Vanilla, Angular — same question, different stacks.

Upgrade to Premium