Here’s a concise JSX specification in 50 lines, blending syntax rules, semantics, behavior, and how JSX transpiles (mostly via Babel) to JavaScript. This aims to mirror what a minimal JSX RFC/spec might look like for language implementers or advanced users.
JSX Specification (in 50 lines)
- JSX is a syntactic sugar for
React.createElement
(or equivalent). - JSX expressions must be wrapped in a single enclosing tag.
- JSX files typically use
.jsx
or.tsx
extensions. - JSX tags resemble HTML but map to JavaScript function calls.
- A JSX element:
<tag attr="value">children</tag>
. - Elements are converted to
React.createElement(type, props, ...children)
. - Type is a string (
"div"
,"span"
) or a React component identifier. - Tag names starting with a lowercase letter map to DOM elements.
- Tag names starting with uppercase letters map to React components.
- Self-closing tags are allowed:
<img />
,<Component />
. - JSX attributes map to object properties in
props
. - Attribute values must be JavaScript expressions inside
{}
. - String literals may be passed without
{}
:<div title="Hi" />
. - Boolean attributes:
<input disabled />
⇒disabled: true
. - The
className
attribute is used instead ofclass
. - The
htmlFor
attribute is used instead offor
. - All other attributes follow camelCase naming (e.g.,
tabIndex
). - Event handlers are camelCase:
onClick
,onChange
, etc. - Children can be strings, numbers, JSX, expressions, or arrays.
- Text content is automatically coerced to string.
- Comments inside JSX use
{/* like this */}
. - Multiple children must be inside a wrapper element or
<>...</>
. - Fragments can be used:
<>...</>
(transpiles toReact.Fragment
). - Conditional rendering:
{condition && <Component />}
. - Ternary operators are supported:
{cond ? A : B}
. - Loops must be in expressions:
{items.map(...)}
. - You cannot use
if
,for
,while
directly in JSX. - Expressions are evaluated at render time.
- JSX supports spread attributes:
<Component {...props} />
. - JSX does not support spreading children.
- Keys must be set when rendering arrays of elements.
- Keys help React optimize reconciliation during re-renders.
- JSX transforms into JavaScript before runtime (via Babel, TypeScript, etc.).
- A JSX tag like
<div id="main">Text</div>
becomes: React.createElement("div", { id: "main" }, "Text")
.- If a component is used:
<MyComp name="x" />
becomes: React.createElement(MyComp, { name: "x" })
.- Nested JSX is recursively converted to nested
createElement
calls. - JSX supports inline functions:
<button onClick={() => foo()} />
. - JSX may be nested in JavaScript logic outside of JSX itself.
- Attributes cannot contain statements — only expressions.
- Dangerous inner HTML must be explicitly set:
dangerouslySetInnerHTML
. - Void elements (e.g.,
<input />
,<img />
) must be self-closing. - Comments outside of JSX use
//
or/* ... */
as usual. - JSX must be in scope with
React
orjsx
factory function (e.g., with Babel). - The JSX pragma (e.g.,
/** @jsx h */
) can change the transformation target. - TypeScript can use
@jsxImportSource
to select a custom JSX runtime. - In React 17+, the new JSX transform eliminates the need to
import React
. - JSX is not HTML — it is closer to JavaScript syntax than browser DOM.
- JSX supports both static and dynamic rendering paths depending on usage.