JSX (JavaScript XML) is a syntax extension for JavaScript created by the React team to facilitate the writing of components.
JSX allows you to write component structure similar to HTML within JavaScript code, combining both languages in a more intuitive way.
- It is very readable: JSX looks like HTML, which makes the code easier to understand.
- It is more expressive: It allows you to describe the user interface structure in a declarative manner.
- It is safer: JSX prevents certain types of errors and even security issues.
It is a mix of HTML and JavaScript that may seem confusing at first, but it is one of the most distinctive features of React (and one of the reasons why it is so popular).
Let’s look at an example of JSX and this “mix of JavaScript and HTML languages”
const element = <h1>Hello, world!</h1>;
In this example,
element
is a variable that contains a fragment of JSX.- As you can see, I didn’t need to put
"
or anything like that (because it’s not a string, it’s a fragment of JSX)
It is not mandatory to use it in React, but it is highly recommended due to its clarity and safety.
Basic JSX Syntax Rules
As we mentioned, JSX looks a lot like HTML, but it is not exactly HTML (it has its own syntax).
Therefore, it has its own rules and some (few) important differences. Here are the main ones:
JSX allows the use of standard HTML tags, such as <div>
, <h1>
, <p>
, etc. However, there are some key differences:
- JSX requires all tags to be closed, even those that do not need it in HTML (like
<br>
,<img>
,<input>
).
// ❌ Incorrect
<img src="photo.jpg">
// ✅ Correct
<img src="photo.jpg" />
- Custom tags: JSX allows the use of custom component names, which must start with an uppercase letter.
<MyComponent />
In JSX, each component or fragment must return a single parent node. For example, this is incorrect:
// ❌ This will throw an error
return (
<h1>Title</h1>
<p>Description</p>
);
To fix it, you can wrap everything in a <div>
:
// ✅ Correct
return (
<div>
<h1>Title</h1>
<p>Description</p>
</div>
);
Or use a Fragment (<>...</>
), which does not add extra nodes to the DOM:
return (
<>
<h1>Title</h1>
<p>Description</p>
</>
);
Instead of using classic HTML attributes (class
, for
, etc.), JSX uses names in camelCase following JavaScript conventions.
HTML | JSX |
---|---|
class | className |
for | htmlFor |
onclick | onClick |
// ❌ Incorrect
<div class="container"></div>
// ✅ Correct
<div className="container"></div>
Comments in JSX are written inside curly braces {}
and use JavaScript comment syntax (/* ... */
).
<div>
{/* This is a comment in JSX */}
<p>Hello, world!</p>
</div>
JSX and Expressiveness with JavaScript
JSX is not a static template: it is embedded JavaScript code with HTML-like syntax… but it is still JavaScript.
Therefore, you can use variables and expressions within the “HTML” fragments (this is one of the main advantages of JSX).
For this, you can pass strings, variables, or even objects. For example,
const user = {
name: "Luis",
age: 22
};
return (
<div>
<h2>Profile</h2>
<p>Name: {user.name}</p> // this prints "Luis"
<p>Age: {user.age}</p> // this prints "22"
</div>
);
In the end, it is just a string interpolation under the hood, with a bit of syntactic sugar (actually, a lot of syntactic sugar).
Similarly, you can use variables and expressions in HTML attributes. For example, for the class (or any other),
const title = "Hello";
const className = "red";
return (
<h1 className={className}>{title} world</h1>
);
You can even put operations, functions, or almost any JavaScript expression inside {}
. For example:
const name = "Ana";
return <p>Hello, {name.toUpperCase()}!</p>;
Although you should not go crazy putting long things inside {}
. If you need to, create a separate variable.
Component Composition
We have mentioned that JSX allows adding new tags (which are precisely the components we will create in React).
By extension, we can also compose components as if they were HTML tags. That is, if you have a Button
component, you can use it like this:
function Button() {
return <button>Click here</button>;
}
function App() {
return (
<div>
<h1>Welcome</h1>
<Button />
</div>
);
}
Note that custom component names must always start with an uppercase letter (<Button />
, not <button />
), so that React distinguishes them from HTML tags.
Internal Functioning Advanced
Even though we don’t see it, under the hood, all our JSX is transformed into standard JavaScript code, fully compatible with the browser.
Specifically, it is converted into calls to React.createElement
. For example, the following JSX code:
const element = <h1 className="title">Hello, world!</h1>;
Will transform into:
const element = React.createElement(
"h1",
{ className: "title" },
"Hello, world!"
);
Which, we can agree, is much less readable, and we wouldn’t want to write it by hand (right? 🤭)
This transformation is performed by tools like Babel or ESBuild or similar, which handle these operations transparently for us.
We are using Vite, which internally uses ESBuild for the conversion.