Lesson 2 / 25

JSX

HTML-like syntax that compiles to function calls.

JavaScript with markup

JSX lets you write markup inside JavaScript: <h1 className="title">Hello, {name}!</h1>. Curly braces embed any JavaScript expression. JSX is not HTML: attributes use camelCase (className, onClick), every element must be closed, and a component returns a single root (use a fragment <>...</> to group siblings). A compiler (Babel, esbuild, SWC, TypeScript) turns JSX into plain function calls that create element objects.

What JSX compiles to, run

I ran this with React 19.3 and react-dom 19.3 on Node.js 22, compiling JSX with esbuild 0.28. Browser-style examples use jsdom 29 as a fake DOM (imported from a small setup-dom.mjs file) and act() to apply updates. esbuild compiles the same line in two modes: the classic transform produces React.createElement calls, and the modern automatic runtime produces jsxs calls imported from react/jsx-runtime, which is why you no longer need to import React in every file.

import { transformSync } from "esbuild";
const source = `const el = <h1 className="title">Hello, {name}!</h1>;`;
console.log(transformSync(source, { loader: "jsx", jsx: "transform" }).code.trim());
console.log(transformSync(source, { loader: "jsx", jsx: "automatic" }).code.trim());

Output:

const el = /* @__PURE__ */ React.createElement("h1", { className: "title" }, "Hello, ", name, "!");
import { jsxs } from "react/jsx-runtime";
const el = /* @__PURE__ */ jsxs("h1", { className: "title", children: [
  "Hello, ",
  name,
  "!"
] });

Expressions, not statements

Inside {} you can use expressions (ternaries, map, function calls) but not if or for statements; compute values above the return instead.

Quick check: Which attribute name is correct in JSX for a CSS class?

  • className
  • class
  • cssClass
  • styleClass
Answer

className — JSX uses DOM property names.