Skip to content

JSX & Elements

JSX looks like HTML, but it is syntax sugar for regular JavaScript function calls. This:

const el = <button className="primary">Click</button>;

compiles (via the modern JSX transform) to roughly:

import { jsx as _jsx } from "react/jsx-runtime";
const el = _jsx("button", { className: "primary", children: "Click" });

The important consequence: JSX is an expression. It evaluates to a value you can store in a variable, return from a function, put in an array, or pass as a prop. It isn’t a template language with its own rules — it’s JavaScript, so { } inside JSX just drops back into a JS expression.

function List({ items, showHeader }) {
return (
<ul>
{showHeader && <li className="header">Items</li>} {/* JS expression */}
{items.map((item) => (
<li key={item.id}>{item.text}</li> {/* JS expression */}
))}
</ul>
);
}

What does _jsx("button", ...) actually return? Not a DOM node — a plain JavaScript object describing what you want:

// Roughly what a React element is:
const el = {
type: "button", // a string for host elements, or a function for components
props: { className: "primary", children: "Click" },
key: null,
// ...internal fields
};

This is the key insight: a React element is a cheap, immutable description — not the real thing. Creating a thousand elements is just creating a thousand small objects. React builds a tree of these descriptions on every render, then compares it to the previous tree to decide what actual DOM to touch (that’s reconciliation, next lesson).

flowchart LR
  jsx["JSX
<button>Click</button>"] -->|compiler| call["jsx('button', props)"]
  call --> obj["element object
{ type, props, key }"]
  obj --> tree["tree of elements
(the description)"]
  tree -->|React| dom["real DOM
(the result)"]
JSX to elements to DOM

The type field tells React what kind of node it is:

  • A string type ("button", "div") is a host element — React knows how to turn it into a real DOM node.
  • A function type (Counter, Greeting) is a component — React calls that function to get more elements, recursively, until it bottoms out in host elements.
<Counter />
// element: { type: Counter (the function), props: {} }
// React calls Counter() → gets more elements → repeats until only host elements remain

This is why a component name must be capitalized in JSX: <Counter /> (capital) means “call the Counter component,” while <counter /> (lowercase) means “create a host element literally named counter.” The capitalization is how the compiler decides between a string type and a variable reference.

What does JSX compile to?
What is a React element?
Why must a component be capitalized in JSX (`<Counter />` not `<counter />`)?
What is `{ }` inside JSX?