What Is JSX Really Doing?
If you were asked "What is a React component?", your first instinct might be to say: "A function that returns some UI." That answer isn't totally wrong — but it's not technically correct either.
- •The precise definition of a React component
- •The difference between JSX and HTML
- •JSX syntax rules and quirks
- •How JSX compiles to JavaScript
- •Practical examples of JSX transformations
A more accurate definition is:
A React component is a function that returns a description of the UI
This distinction matters, because React components are not returning literal HTML.
We can't put real HTML inside JavaScript — so what exactly are we returning?
Meet JSX
JSX is the "HTML-ish" syntax that lets you write markup inside your JavaScript files. It feels like HTML, but it's actually syntactic sugar that compiles into plain JavaScript at build time.
Before we get into what JSX really is, let's first explore some important rules, quirks, and gotchas that every React developer should know.
Multi-Line JSX and the ASI Trap
A common early confusion happens when returning multi-line JSX:
export default function WhatIsJSX() {
return <main>
<h1>This is JSX</h1>
<h2>JSX <i>looks</i> like HTML</h2>
<h4>(but it's not)</h4>
<p>
JSX is inspired by HTML and allows you to
write HTML-ish looking syntax inside your
React Components.
</p>
</main>
}This works, but it looks odd — the opening <main> sits on the same line as return.
You might try formatting it more naturally:
export default function WhatIsJSX() {
return
<main>...</main>
}But that fails with a subtle JavaScript issue:
Automatic Semicolon Insertion (ASI) puts a semicolon right after return.
JavaScript interprets it as:
return;The fix is the standard JSX pattern:
return (
<main>
...
</main>
)You Can Only Return One Top-Level Element
Consider:
export default function Authors() {
return (
<h2>Authors</h2>
<ul>
<li>Tyler</li>
<li>Ben</li>
<li>Alex</li>
</ul>
)
}This looks valid… until React throws:
Adjacent JSX elements must be wrapped in an enclosing tag
You must return a single top-level element.
You could wrap everything in a <div>:
return (
<div>
<h2>Authors</h2>
<ul>...</ul>
</div>
)But now you've introduced unnecessary markup.
The clean, semantic fix is:
React.Fragment
return (
<React.Fragment>
<h2>Authors</h2>
<ul>...</ul>
</React.Fragment>
)Or its shorthand:
<>
<h2>Authors</h2>
<ul>...</ul>
</>Self-Closing Tags Must Explicitly Close
In HTML, this is fine:
<img src="avatar.png">Not in JSX.
JSX requires self-closing tags to include /:
<img />
<input />
<br />So:
<img src="search.png" alt="search icon" />
<br />
<input name="term" type="text" />class → className and Other Attribute Differences
You can't write:
<img class="avatar" />because class is a reserved JavaScript keyword.
React uses className instead:
<img className="avatar" />Likewise, HTML attributes with dashes must be camelCased:
<rect strokeWidth="5" fillOpacity="0.5" />Using Expressions in JSX
Any JavaScript expression must be wrapped in {}:
<h1>Hello, {name}</h1>
<p>Today is {new Date().toLocaleDateString()}</p>
<p>{2 + 2}</p>Showing Nothing: Returning null
A component can render nothing by returning null:
if (isLoading()) {
return null
}
return <main>...</main>Conditional Rendering in React
Unlike Angular and Vue, React doesn't provide special templating syntax.
It uses plain JavaScript:
1. if/else
if (authed) {
return <h1>Welcome back!</h1>
} else {
return <h1>Please log in</h1>
}2. Ternary operator
return authed
? <h1>Welcome back!</h1>
: <h1>Please log in</h1>3. Ternary inside JSX
<Logo />
{authed ? <Dashboard /> : <Login />}4. Logical AND (&&)
{showWarning() && <Warning />}Capitalization Matters
React assumes:
- lowercase = native HTML tags
- Capitalized = custom React components
So:
<button /> → HTML button
<Button /> → your own componentRendering Lists with .map
In Angular or Vue, you have template syntax:
Vue:
<li v-for="tweet in tweets">{{ tweet.text }}</li>Angular:
<li *ngFor="let tweet of tweets">{{ tweet.text }}</li>In React, you use plain JavaScript:
<ul>
{tweets.map(tweet => (
<li key={tweet.id}>{tweet.text}</li>
))}
</ul>Every element in a list must include a unique key so React can efficiently update the DOM.
So… What Is JSX Actually?
Here's the part that surprises most people:
JSX is not HTML. JSX is not even "almost HTML." JSX is just JavaScript.
At build time, a tool like Babel transforms this:
function Hello() {
return <h1>Hello World</h1>
}into this:
import { jsx as _jsx } from "react/jsx-runtime"
function Hello() {
return _jsx("h1", { children: "Hello World" })
}What the browser sees is only JavaScript.
tl;dr — JSX is JavaScript with a fancy disguise.
Summary
Understanding JSX is crucial for React development. Remember:
- • JSX is syntactic sugar that compiles to JavaScript
- • React components return descriptions of UI, not literal HTML
- • JSX has specific rules (self-closing tags, className, etc.)
- • Conditional rendering uses plain JavaScript, not special syntax
- • Capitalization distinguishes HTML tags from React components