JSX: HTML in Your JavaScript
What JSX really is, the three rules that follow from it, and Fragments.
In App.jsx you wrote return <h1>Hello, React!</h1>; — HTML, sitting inside a JavaScript function. If you tried that in JavaScript Fundamentals, you'd get an instant syntax error. So what's going on?
That syntax is JSX (JavaScript XML) — an extension to JavaScript that looks like HTML but isn't. Browsers can't read it. Before your code runs, Vite's compiler translates every JSX tag into a plain function call:
// What you write:
const el = <button className="btn">Click me</button>;
// What the browser actually receives:
const el = React.createElement('button', { className: 'btn' }, 'Click me');Hold onto this one sentence — it explains every JSX rule you're about to learn: every JSX tag is a function call in disguise.
What happens to JSX before your code runs in the browser?
- AThe build tool compiles it to React.createElement() calls — plain JavaScript
- BThe browser understands JSX natively
- CIt is converted to a separate HTML file
- DReact reads the JSX as a string at runtime
Because JSX is secretly JavaScript, three rules follow — each one directly caused by the 'function call in disguise' fact:
// Rule 1: className, not class
<div className="card">...</div>
// Rule 2: close EVERY tag — self-close the empty ones
<img src="photo.jpg" alt="cat" />
<input type="text" />
<br />
// Rule 3: return ONE root element
return (
<div>
<h1>Title</h1>
<p>Body</p>
</div>
);- Why
className?classis a reserved JS keyword (andfor→htmlFor) - Why close every tag? A compiler isn't forgiving like HTML
- Why one root? A
returnproduces exactly one value
Fix the JSX — use the correct React attribute for a CSS class:
<div _____="container">Hello</div>Rule 3 has an annoying side effect: sometimes you don't want a wrapper <div> polluting your HTML (extra divs break table rows and grid layouts). React's answer is the Fragment — an invisible wrapper written as empty tags:
return (
<>
<h1>Title</h1>
<p>Body</p>
</>
);The Fragment satisfies the one-root rule but adds no element to the real DOM — the <h1> and <p> land side by side, wrapper-free. Use a <div> when you actually want a container (say, to style it); use <>...</> when you only need to group.
Why can't a component return two sibling elements without a wrapper or Fragment?
- AJSX compiles to a function call — one return can only produce one value
- BReact limits components to one element for performance
- CHTML doesn't allow sibling elements
- DYou can — there is no such restriction
How many elements does this add to the real DOM?
return (
<>
<h1>Menu</h1>
<p>Pick a dish</p>
</>
);- A2 — the Fragment itself adds nothing
- B3 — Fragment, h1, and p
- C1 — everything merges into the Fragment
- D0 — Fragments prevent rendering
- JSX looks like HTML but compiles to
React.createElement()calls — every tag is a function call in disguise. - Use
classNameinstead ofclass(a reserved JavaScript keyword). - Close every tag — self-close empty ones like
<img />and<input />. - A component returns one root element, because one
returnproduces one value. - A Fragment
<>...</>groups siblings without adding anything to the real DOM.
So far our JSX is static. Next lesson: the curly braces {} that pour live JavaScript data into it — the moment JSX becomes actually powerful.