Topic 1.1
What JSX Is
In one line
JSX is a syntax extension for JavaScript that lets you write HTML-like tags inside your code; a compiler turns every tag into an ordinary function call that returns a plain object describing the UI.
Think of it like this
Writing a shopping list in shorthand. You write 2 milk, 1 bread because it is quick to read, but the shopkeeper understands it as "two bottles of milk and one loaf of bread". JSX is shorthand for UI. You write <h1>Hello</h1> because it looks like the page you want. Before the browser runs it, a tool translates the shorthand into the long form: a JavaScript function call.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- JSX
- HTML-like tags written inside JavaScript, such as
<h1>Hi</h1>. Short for JavaScript XML. - Syntax extension
- Extra grammar added to a language. JSX adds tags to JavaScript.
- Compiler
- A program that turns code into other code. Here it turns JSX into plain JavaScript function calls.
- Expression
- A piece of code that produces a value, like
2 + 3,nameor<p>Hi</p>. - jsx() call
- The function call a JSX tag turns into. It returns a plain object describing the element.
- createElement
- React's older function for making elements by hand:
createElement("p", null, "Hi"). Still works. - React element
- The plain object a JSX tag produces. It describes what should be on screen; it is not a real DOM element.
- Separation of concerns
- Keeping each job in its own place. React groups by piece of UI, not by file type.
Step by step
01You write tags inside JavaScript
Here is a small component. The part after return looks like HTML, but it lives inside a JavaScript function and uses a JavaScript variable, name.
function Greeting() {
const name = "Asha";
return <h1 className="title">Hello, {name}!</h1>;
}02The compiler turns each tag into a function call
Before the browser sees this file, the compiler rewrites the tag. The tag name becomes the first argument; the attributes and the children become one object, the props. Nothing else in the file changes.
import { jsxs as _jsxs } from "react/jsx-runtime";
function Greeting() {
const name = "Asha";
return _jsxs("h1", { className: "title", children: ["Hello, ", name, "!"] });
}03The call returns a plain object
Calling jsx() doesn't touch the page. It returns a small object, a React element, that says "an h1 with class title and this text". It is a description, like a drawing of a house is not a house.
04React DOM builds the real page from the description
When you render, react-dom reads the element objects and creates (or updates) real DOM elements to match. JSX → function calls → element objects → DOM.
05Because it is a value, you can move it around
Since a tag is really a function call, you can put it anywhere a value fits: in a variable, in an if, in an array, as an argument. The live examples below do exactly that.
Try it yourself
- 1
Change the hour
In "JSX is a value", predict which heading appears when
houris12. Change it and check. (12 < 12is false, so it's the evening greeting.) - 2
Add a third card with function calls
In the first example, write a third card with
createElementthat saysBye!in anh2, and render it inside<main>after the others. Notice how much harder the nested calls are to read than the JSX. - 3
Pass JSX as an argument
Write
function framed(content) { return <div className="card">{content}</div>; }and render{framed(<b>Inside a frame</b>)}. JSX went into a function and came back wrapped.
Code & diagrams
Two identical cards: the JSX version and the hand-written `createElement` version produce the same kind of object. JSX is only a nicer way to write the calls.
Preview
Console
Nothing logged yet.Expected console output
JSX gives a div with class card
Calls give a div with class card`greeting` is an object, so it can sit in a variable and be dropped into the page later with `{greeting}`. Change `hour` to 18 to see the other greeting.
Preview
Console
Nothing logged yet.Expected console output
greeting is an object// Input (JSX)
<div className="card">
<h2>Hello, Asha!</h2>
<p>You have 3 new messages.</p>
</div>
// Output (real sucrase output, tidied): one call per tag
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
_jsxs("div", {
className: "card",
children: [
_jsx("h2", { children: "Hello, Asha!" }),
_jsx("p", { children: "You have 3 new messages." }),
],
});Break it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Put quotes around JSX
In the second example, change the morning greeting to "<h2>Good morning, {name}!</h2>" (with double quotes around it).
Myth vs fact
Myth
JSX is HTML inside JavaScript.
Fact
It only looks like HTML. It is JavaScript syntax that compiles to function calls, with its own rules: className, camelCase attributes, every tag closed (Topic 1.2).
Myth
Browsers understand JSX.
Fact
No browser runs JSX. A compiler turns it into plain JavaScript first, either in your build tool (Vite, Next.js) or, on Hectal, in the live editor.
Myth
You must use JSX to use React.
Fact
JSX is optional. createElement (or jsx() from react/jsx-runtime) builds the same elements. JSX is simply what nearly everyone uses.
Myth
Mixing markup and logic breaks separation of concerns.
Fact
It separates by component instead of by file type. The markup and logic of one button change together, so keeping them together is the cleaner split.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
JSX has a written specification (facebook/jsx on GitHub) that defines only the syntax, not what it means. The meaning comes from the compiler setting:
jsx: "react-jsx"intsconfig.json, or the JSX options of Babel, SWC, esbuild or Oxc. - ▸
The automatic runtime (introduced with React 17) imports
jsx/jsxsfromreact/jsx-runtimefor you. Before it, the classic runtime compiled tags toReact.createElement(...), so every file neededimport React from "react". That is why old code starts with that import even whenReactlooks unused. - ▸
In development builds the compiler emits
jsxDEV(...)fromreact/jsx-dev-runtimeinstead, passing extra information (such as whether the children were static) so React can print better warnings. The live editor here compiles in production mode (jsx/jsxs) but still runs React's development build, so you still see its warnings.
Remember this
- 1
JSX stands for JavaScript XML. It is a syntax extension: extra grammar added on top of JavaScript, the way a dialect adds a few words to a language. It lets you write tags such as
<button>Save</button>in the middle of JavaScript code. JSX is not HTML (it has its own rules, Topic 1.2), not a string (there are no quotes around it), and not a template language (it has no special loops or ifs; you use plain JavaScript for those, Topic 1.3). - 2
Browsers do not understand JSX. Before your code runs, a compiler (a program that turns code into other code) rewrites every tag into a function call. With React's automatic JSX runtime,
<h1 className="title">Hello</h1>becomesjsx("h1", { className: "title", children: "Hello" }), imported fromreact/jsx-runtime. Tools that do this include Babel, SWC, esbuild, Oxc, TypeScript and sucrase (which compiles the examples on this page). You never calljsx()yourself; you'll look inside it in Topic 1.7. - 3
Because each tag becomes a function call, JSX is an expression: something that produces a value. You can store JSX in a variable, return it from a function, pass it as an argument, put it in an array or choose between two pieces with a ternary. Anything you can do with a value in JavaScript, you can do with JSX.
- 4
Why mix markup and logic in one file? Older web code split files by technology: HTML in one file, JavaScript in another. But the markup of a button and the code that decides what it shows always change together. React splits code by concern instead: one component holds the markup, the logic and (often) the styles for one piece of the screen. JSX is what makes that comfortable to write.
- 5
JSX is optional. You can build any React app by calling
createElement("h1", null, "Hello")yourself, and a few projects do. In practice almost every React codebase, tutorial and job uses JSX, because nested tags are far easier to read than nested function calls. Files that contain JSX usually end in.jsx(or.tsxwith TypeScript, Phase 12). - 6
JSX is not only for React. The syntax just produces function calls, so other libraries (Preact, Solid, Vue's JSX mode) use it with their own functions. Which function the tags turn into is a compiler setting, which is why your build tool needs to know you're using React.
Explain it without notes
What is JSX, and what happens to it before the browser runs your code?
Why can you store JSX in a variable or return it from a function?
Why does React put markup and logic in the same file?
Is JSX required to use React? What is the alternative?
Practice
Rewrite <p className="note">Saved!</p> using createElement.
Write a function label(text) that returns a <strong> element containing the text, and use it twice inside a <p>.
Trade-offs
- ↔
JSX needs a compile step. That's free in any modern toolchain, but a page that loads React from a
<script>tag with no build has to usecreateElement(or a tagged-template library such as htm) instead. - ↔
Keeping markup and logic together is clear for small components; large components that mix too much logic into their JSX become hard to read, which is why you'll learn to split components (Phase 2) and extract hooks (Phase 10).
Done when you can
I can say what JSX is and why browsers can't run it directly.
I can describe what a JSX tag compiles to.
I can store JSX in a variable and return it from a function.
I can explain why React keeps markup and logic together.
I know JSX is optional and what
createElementdoes.