If you've ever tried building websites, you've probably heard of React. It's super popular these days, and developers love it because it makes creating websites easier and faster.
Want to know something cool?
There's this thing called JSX that makes working with React feel like a breeze. Once you understand the basics, you'll be able to build impressive websites quickly. This guide will help you master JSX step by step.
Here's what we'll cover: First, we'll explain what JSX actually is. Then, we'll show you how it connects HTML and JavaScript together, making your code cleaner and easier to understand.
After reading this guide, you'll learn the basics of JSX and how to use it to create React websites in a simple way.
What is JSX
JSX is a special syntax that extends JavaScript to work with React. It lets you write HTML-style code directly in your JavaScript files, making it easier to create and understand user interface components. Rather than keeping HTML and JavaScript separate, JSX brings them together in one clean format.
Why do we use JSX
The main benefit of using JSX, is that it makes React development easier in several ways. It lets you write code that looks like HTML right inside your JavaScript files, which makes it simple to understand what your interface will look like.
Instead of writing complex code 👀 with React.createElement
, you can write clear, straightforward markup. You can also add JavaScript expressions directly in your markup to make it dynamic, and the development tools will help you catch mistakes early with helpful error messages.
While JSX is powerful, it does come with a few challenges.
First, if you're new to React, it might take some time to get used to writing HTML-style code inside JavaScript - this mix of syntax can feel a bit strange at first.
Moreover, before your code can run in a web browser, you need to use a tool called Babel to convert JSX into regular JavaScript that browsers can understand. This means you'll need an extra step when building your project.
How does JSX works
JSX works by allowing developers to write XML-like syntax, which is then transformed into JavaScript function calls. Here are some core concepts and syntax rules of JSX:
- Embedding Expressions: You can use curly braces
{}
to embed JavaScript expressions within JSX. For example,<h1>{user.name}</h1>
whereuser.name
is a JavaScript expression. - Components: JSX can represent either HTML elements or custom React components. Components can have children and can be nested.
- Attributes: JSX uses camelCase for attribute naming. For example,
className
instead ofclass
andhtmlFor
instead offor
. - Self-Closing Tags: If an element has no children, you can use a self-closing tag like
<img src="image.jpg" />
. - Single Parent Element: Every JSX expression must have a single parent element. If you need to return multiple elements, wrap them in a single parent element or use React Fragments (
<> ... </>
).
Compiling JSX into JavaScript
In practice, we often wind up with pretty significant tree structures in our React code. Here is an example using plain JavaScript code:
React.createElement(
'div',
null,
React.createElement(
'h1',
null,
`Hello, ${name}!`
),
React.createElement(
'p',
null,
'Welcome to our website.'
),
React.createElement(
'img',
{ src: 'welcome.jpg', alt: 'Welcome' }
)
);
Pretty challenging to read, right? Here's that same example in JSX:
//In JSX:
const element = (
<div>
<h1>Hello, {name}!</h1>
<p>Welcome to our website.</p>
<img src="welcome.jpg" alt="Welcome" />
</div>
);
In the example above, we wrap the JSX in parentheses, like this:
const element = (
<div> … </div>
);
This is done purely for formatting purposes. It allows us to push the JSX onto the next line. If we wanted to, we could skip the parentheses and keep it "inline", like this:
const element = <div>
…
</div>;
This is totally valid, but it's a bit harder to read; things don't “line up” as nicely. And so, it's convention in React to push the JSX onto its own line, and to use parentheses to ensure it works correctly.
This is a trick we can use even outside of JSX/React. Parentheses can be used to improve formatting, like this:
const friendlyGreeting = (
"Totally valid way to format things!"
)
Compiling vs Transpiling
If we try to run this JSX code in the browser, we'll get an error. JavaScript engines don't understand JSX, they only understand JavaScript. And so we need to "compile" our code into plain JS.
Don't worry - this all happens automatically when you're building your app using a tool called Babel ✨
Here's what you really need to know: When you write JSX, it gets turned into regular JavaScript that uses React.createElement
. So by the time your code runs in someone's web browser, all that nice JSX syntax has been converted into plain JavaScript with lots of nested React.createElement
calls.
In formal computer-science terms, compiling typically refers to the process of taking human-readable code and transforming it into machine-readable code.
For example, a compiler might take a high-level language like Python and convert it into machine code, low-level instructions that appear like hebrew to us ↓
⠀ 6⠀ ⠀5⠀ 5 ⠀ 5 ⠀ ⠀5 ⠀ ⠀ 6 bits
[ op | rs | rt | rd | shamt | funct ⠀] R-type
[ op | rs | rt | address/immediate⠀] I-type
[ op | ⠀ ⠀ ⠀ target address ⠀ ⠀ ⠀] J-type
The term Transpiling, by constrast, typically refers to taking one high-level language and transforming it into another high-level language.
Keep in mind: we're speaking about formal computer-science terminology. For most of us, "compile" isn't defined so precisely. I think when most developers use the term "compile", we're really just talking about transforming code from one form to another.
File extensions and JSX
You might noticed that a React file is called index.js
. You might be wondering - shouldn't we name it index.jsx
since we're using JSX in it?
Well, here's a fun fact: back when React was new, you actually had to use the .jsx
extension for any file with JSX in it. It was like putting up a sign saying "Hey compiler, this file needs special treatment!"
But developers found this pretty annoying. Having to rename files every time you added or removed JSX was a real hassle!
So they made things easier. Now you can just use a regular .js
file and add JSX to it - no problem! The tools that process your code are smart enough to handle it.
That said, some folks still like using .jsx
files just to make it super clear which files have JSX in them. And that's totally fine! You can do whatever works best for you. 👍🏼
Expression Slots
In JSX, when we write content between tags, it's treated as regular text by default.
However, we can use curly brackets {}
to include JavaScript expressions - this lets us add dynamic content like variables or calculations. These are called expression slots, and they're a key feature that makes JSX powerful.
Just remember that you can only put expressions inside these brackets (like variables or simple calculations), not full JavaScript statements (like if-else blocks).
This is because JSX eventually gets converted into React.createElement()
function calls behind the scenes. In the code playground below { shoppingCard.length }
is an expression slot, and it’s totally valid in JSX.
Try to play around 🎮 with the code below to see if you can add more expressions and see what happens!
Comments in JSX
To add a comment in JSX, we use an expression slot:
const element = (
<div>
{/* Your comment! */}
</div>
);
We specifically need to use the multi-line comment syntax ( /* */
) instead of the single-line syntax ( //
). This is because the single-line syntax comments everything out, including the closing }
for the expression slot!
const element = (
<div>
All the line ↓ below ↓ is commented, including the "}"
{// Your comment can be added here! }
</div>
);
Attribute in expression slot
We can use the same trick for dynamic attribute values!
Here's an example:
const uniqueId = 'content-wrapper';
const element = (
<main id={uniqueId}>
Hello World
</main>
);
As we saw above, the squiggly brackets ( {}
) allow us to create an expression slot. This time, we're creating a slot for the value of the id
attribute.
Here’s how it compiles:
const element = React.createElement(
'main',
{
id: uniqueId,
},
'Hello World'
);
For comparison, here's what it looks like without an expression slot, when the value for id
is fixed:
const element = (
<main id="content-wrapper">
Hello World
</main>
);
// Will get compile as:
const compiledElement = React.createElement(
'main',
{
id: "content-wrapper",
},
'Hello World'
);
We can use attribute expression slots whenever we need the values to be dynamic. We can put any valid JavaScript expression in here, not just variables:
const userEmail = 'sumeet@thegreat.com';
const element = (
<main id={userEmail.replace('@', '-')}>
Hello World
</main>
);
// Will get compiled as:
const compiledElement = React.createElement(
'main',
{
id: userEmail.replace('@', '-'),
},
'Hello World'
);
Here's something cool to know - when we compile JSX code, we don't actually run any of the code yet!
Let's look at our example: we wrote some code to change the userEmail
from having an @
symbol to having a - symbol instead. But this change doesn't happen during compilation.
When JSX turns into regular JavaScript, it just copies whatever's inside the curly braces
{}
without doing anything with it. The actual work (like changing @
to -
) happens later when someone uses your website in their browser.It's kind of like writing a recipe versus actually cooking the food. When you write down a recipe (compilation time), you're just putting instructions on paper. The actual cooking (runtime) happens later when someone follows those instructions in their kitchen (the browser)!
Type Coercion
At run-time, React will automatically convert types as needed when supplying attributes in expression slots. For example, these two elements are identical:
// This works:
<input required="true" />
// And so does this!
<input required={true} />
In HTML, it's possible to set attributes to true
by specifying only the key, like this:
<inputrequired>
This same pattern has been implemented in JSX; these two elements are equivalent:
<inputrequired/>
<inputrequired={true}/>
Honestly, though, I don't recommend doing this. I prefer to spell it out, and write required={true}
.
The whitespace Gotcha
Consider the example in the playground below:
Notice how there's no space between the text and the number? Instead of Cart: 123
, it's showing as: Cart:123
. To understand why this happens, let's consider how this JSX compiles to JavaScript:
const element = React.createElement(
'div',
{},
React.createElement(
'strong',
{},
'Cart:'
),
numberOfArticles
);
Our <div>
has two children, the <strong>
tag and the numberOfArticles
variable.
Remember, JSX doesn't compile to HTML, it compiles to JavaScript. And when that JavaScript is executed, it's only going to create and append two HTML nodes:
- A
<strong>
tag with some text. - A text node, for the number
123
.
So how do we fix it? The most common solution is to add a single whitespace character, in curly braces:
<div>
<strong>Cart:</strong>
{' '}
{numberOfArticles}
</div>
Here's how this compiles:
const element = React.createElement(
'div',
{},
React.createElement(
'strong',
{},
'Cart:'
),
' ',
numberOfArticles
);
Ending
We've explored what JSX is all about - it's basically a cool way to mix JavaScript and HTML in React. Looking back at what we've learned, JSX does more than just show stuff on the screen - it changes how we build our apps, making it easier and more natural for developers to write code that just works.
🔍. Similar posts
Simplifying Layouts With React Fragments
18 Jan 2025
Stop Installing Node Modules on Your Docker Host - Install Them in the Container Instead
14 Jan 2025
An Easy to Understand React Component Introduction for Beginners
14 Jan 2025