What is JSX?
In the previous chapters, we've already seen what JSX is and have even put it into action. But let's explore more details of this amazing extension to JavaScript's syntax, specifically made for React.
To start with, let's review what JSX is.
It was developed by Meta (formerly Facebook) to be used alongside React, and released shortly after React in 2013.
As you already know at this stage, JSX is meant to simplify the construction of React elements, otherwise done by calling createElement()
. If offers an HTML-like (or XML-like) syntax to denote React elements in JavaScript source code.
Keep in mind that JSX is neither a part of the ECMAScript standard, nor of the HTML or XML standards. It's purely a standalone specification which implementors can go through and implement in their JavaScript parsers, like Babel.
The JSX specification, alongside the motivation behind JSX, can be read at https://facebook.github.io/jsx/.
As we've seen in the previous chapters, JSX is absolutely NOT a requirement in React apps, per se. But it's so compact and rewarding over the createElement()
-call approach that we feel that when we talk React, we are bound to talk JSX. We just feel at home while writing JSX.
Stating it once more, JSX is not a part of React — it's a separate syntactic tool to help React developers easily create React elements using a syntax similar to that of one of the most rudimentary, yet paramount, web technologies, i.e. HTML.
JSX is clearly one of the many reasons of the popularity of React, even though it's a disparate feature.
Moving on, if we delve into a technical discussion, JSX is precisely another type of expression in JavaScript. JSX is not a statement; it's purely an expression. Hence, wherever JavaScript expects an expression, we can indeed provide JSX there.
For example, we can write JSX as an attribute's vaue of a JSX element; we can write JSX as an array item; we can pass on JSX to a function as an argument; and so on. We'll see such examples soon in this course.
JSX elements
As we've gotten super familiar with it, JSX elements are simply syntactic sugar over creating React elements manually via createElement()
.
The syntax of JSX elements resembles that of HTML elements.
That is, we have opening and closing tags denoted using angle brackes (<
and >
). This makes perfect sense because all UI libraries/frameworks, at the end of the day, create HTML elements. So why not use an HTML-like syntax if at the end that code is to be used to create HTML elements anyway.
React comes with a handful of predefined elements which are its abstractions over HTML DOM elements. And they are represented just like they'd be in actual HTML source code.
For example, if we want to create an <h1>
HTML element, we'd write the following JSX:
<h1>This is JSX</h1>
Similarly, if we want to create a <div>
element, we'd write the following JSX:
<div>A simple div</div>
And so on and so forth.
All HTML elements are available in React with the exact same tag names.
And not just this, but JSX elements can also be used to instantiate components.
For example, in the code below, we instantiate a <Greeting>
element out of the Greeting
component:
function Greeting() {
return (
<h1>JSX is superb!</h1>
);
}
const element = <Greeting></Greeting>;
Simple, isn't this?
One extremely important thing to note while instantiating components via JSX elements is that the name of the component must be capitalized (i.e. begin with a capital letter). This is NOT a convention; it's a must.
The following snippet expands upon this.
Capitalization of component names required for JSX elements
If the name of a component doesn't begin with a capital letter, the JSX element used to instantiate it would get converted into a createElement()
call where the first argument is not a reference to the component, but instead a string containing the name of the component.
And this would simply lead to unexpected results.
Here's an illustration of this idea.
In the following code, we have a component called greeting
(with the first letter in lower case) and then, as always, instantiate it via <greeting>
:
function greeting() {
return 'JSX is simple';
}
const element = <greeting></greeting>;
However, when we run the code, we notice nothing on the document. What possibly could've gone wrong?
The console might help us out. Well, yes, we do see a warning messaged logged in the console:
Before making sense of this warning, let's see what the JSX converts to:
const element = React.createElement('greeting', null);
Carefully notice the first argument here. It's a string, NOT a function, contrary to our expectation.
Recall from the previous React Elements chapter that when the first argument of createElement()
is a string, it represents a DOM element. Now since there is no such DOM element as <greeting>
in the browser, we get the warning above.
It's also important to note that this element (representing a non-existent DOM element) does get rendered out on to the document but without any content whatsoever inside it. In the link above, open up Developer Tools and inspect the DOM tree of the page; you'll notice a <greeting>
element in there.
Anyways, the solution to this complex mess is pretty simple: capitalize the component's name.
Let's do this now:
function Greeting() {
return 'JSX is simple';
}
const element = <Greeting></Greeting>;
And it works now!
With this simple idea of capitalization, of a component name, a JSX parser is easily able to distinguish between a React element representing a DOM element and a React element representing a component instance.
React doesn't have to maintain a list of DOM element names to check against the tag name of a given JSX element in order to determine whether it represents a DOM element or a component instance — this distinction is right there in the JSX code itself.
Moving on, if a JSX element doesn't have any children, we could omit its closing tag.
So, the <Greeting>
element shown above could be more compactly denoted as follows:
function Greeting() {
return (
<h1>JSX is superb!</h1>
);
}
const element = <Greeting/>;
Keep in mind that when we do omit the closing tag, then it's a requirement to put a forward slash (/
) at the end inside the starting tag.
Likewise, the following is invalid JSX:
function Greeting() {
return (
<h1>JSX is superb!</h1>
);
}
// The closing / is missing in the tag.
const element = <Greeting>;
This applies to React elements representing DOM elements as well.
For example, in the following code, we denote an <img>
element as a single tag but without a /
inside it (as we're used to doing in HTML sometimes) and thus get an error logged:
// The closing / is missing in the <img> tag.
const element = (
<img src="image.png" alt="Some image">
);
The correct way to express this is as follows:
const element = (
<img src="image.png" alt="Some image" />
);
The <img>
tag here clearly includes the /
character at its end and likewise produces absolutely valid JSX.
Always make sure to include /
at the end of tags in your JSX that don't have corresponding closing tags, because it could otherwise lead to errors.
JSX attributes
Since JSX elements mirror the syntax of HTML/XML elements, it shouldn't be any surprising to know that we could set attributes on JSX elements.
JSX attributes work pretty much the same way as attributes on HTML/XML elements. But it's paramount to always remember that JSX elements are simplifications over createElement()
and so, by that means, attributes merely represent given props of React elements.
There's almost nothing special to learn for JSX attributes apart from the fact they're just props of the underlying element. So the way those props work is exactly the way the corresponding JSX attributes work. As simple as that.
The most important thing to remember is that, except for data-
and aria-
attributes, all JSX attributes are represented in the camel-case convention, even though the corresponding HTML attributes aren't.
For example, in HTML we have the contenteditable
attribute, yet in JSX we have the contentEditable
attribute. Similarly, in HTML we have readonly
, while in JSX we have readOnly
. In HTML, we have accept-charset
, while in JSX we have acceptCharset
. And so on and so forth.
If we consider the fact that JSX is closer to JavaScript than HTML — in fact, it is JavaScript at the end of the day — this won't be any hard to wrap the mind around.
Still let's have a quick formal dicussion on this.
Why are DOM-related props camel-cased in React?
This is a very good question, and one which might've popped up in your mind as well. The answer to it is fairly simple.
Restating the question: Why exactly are DOM-related props in React, or simply DOM-related attributes of JSX elements (representing DOM elements) camel-cased?
For instance, why do we have contentEditable
(in React) instead of contenteditable
(in HTML)? Why do we have acceptCharset
(in React) instead of accept-charset
(in HTML)?
Well, there are mainly two reasons for this.
If you carefully inspect it, many of the HTML attributes are represented as camel-cased properties in the DOM. We don't need to go far away to confirm this. The contenteditable
attribute in HTML is represented as contentEditable
in the DOM, itself.
And because React is a library that works on top of the DOM, it makes sense to stick to a naming convention that's used by the DOM.
So this is one reason why React names DOM-related props in the camel-case convention. That is, using camel-case goes with the very nomenclature used in the DOM itself.
The second reason is more related to code consistency.
Imagine if these props weren't camel-cased. And at the same time, also suppose that we had certain props not related to the DOM at all, i.e. they were just meant for driving the logic of the React app, for e.g. firstName
, items
, etc.
With this scenario set up, we're very likely to be naming the DOM-unrelated props in camel case, as that's what we're used to doing while coding in JavaScript. But the DOM-related props would be in lower case.
If we were to pass both these kinds of props to a component, this difference in the naming of the props would've ultimately led to inconsistency.
By sticking to camel case for almost all DOM-related props, consistency in the names of props, both related and unrelated to the DOM, can be achieved.
data-
and aria-
attributes in React
There's an exception to the camel-cased prop naming discussed above.
That is, if we wish to set any data-
or aria-
attribute on any React element, we don't have to worry about camel-casing it — we write it just as we'd do in plain HTML.
For example, suppose we want to set the data-src
attribute on an <img>
React element.
This would be accomplished as follows:
const element = (
<img data-src="image.png" />
);
Let's consider some commonly-used JSX attributes.
First, we have the className
attribute — perhaps the most important attribute driving the styling of web apps:
const element = (
<h2 className="text-blue">Hello World!</h2>
);
.text-blue {
color: blue
}
Hello World!
Next, we have style
for inline-styling elements. The style
prop is another one of the many miniature features React provides to us in order to ease UI development.
Setting inline styles on elements from within JavaScript, though not recommended as the go-to approach for styling, is not a very rare thing — it's frequently observed in applications.
In the HTML DOM, we have the style
property which holds an object with loads and loads of style properties on it that we could assign strings to in order to apply the given styles to a given DOM element.
If we want to, we can even take a whole string of CSS text and dump it into the cssText
property of the style
object to bulk-apply many styles at once.
style
property in JavaScript CSSOM — The style
Property.However, we can't assign an object literal, holding the styles, to the style
property as we can do with the style
prop in React. This just does NOT work in the DOM, which explains that React improvises a little bit with style
as well, and rightly so.
With the ability of providing an object literal to style
, holding all the required styles, we always remains in the context of typing actual code while laying out our styles, and never ever have to switch to the context of working in a string (which is tedious).
style
attribute, we get autocompletion. And that's simply amazing!Let's take an example of using style
:
const element = (
<h2 style={{ marginLeft: '50px', color: 'orange' }}>Hello World!</h2>
);
Hello World!
Besides this, if we assign a number to a given style property, let's say width
, or maxWidth
, or maybe even left
, React automatically converts it to the string '<number>px'
, where <number> represents the number entered.
So based on this, we could redefine the marginLeft
property above as shown below, without changing the output of the code:
const element = (
<h2 style={{ marginLeft: 50, color: 'orange' }}>Hello World!</h2>
);
Hello World!
marginLeft: 50
is effectively the same as saying marginLeft: '50px'
.
Moving on, another attribute we might run into while developing our applications is id
:
const element = (
<div id="d1">Hello World!</div>
);
#d1 {
background-color: orange;
color: white;
width: 100px;
}
Hello World!
Quite basic.
Apart from this, when a particular attribute is merely set on a JSX element, without a corresponding value, its value defaults to the Boolean true
.
Once again, this idea has been borrowed from HTML where omitting the value of a given attribute (specifically, a Boolean attribute) defaults it to "true"
.
So for example, the following JSX, setting the disabled
attribute,
const element = (
<button disabled>A disabled button</button>
);
is effectively the same as:
const element = (
<button disabled={true}>A disabled button</button>
);
And this produces the following output:
Embedding code inside JSX
JSX itself is just a static representation of a bunch of createElement()
calls. But because createElement()
is JavaScript, it seems sensible to be able to switch to 'JavaScript mode' while writing JSX and, thus, make the JSX dynamic in that way.
This mode switching is done by using a pair of curly braces ({}
) where JSX code is expected.
A pair of curly braces ({}
) instructs the JSX parser that JavaScript code — or more precisely speaking, a JavaScript expression — follows.
Let's consider a few examples.
In the following JSX code, we create an <h1>
element whose text content refers to a variable language
:
let language = 'JSX';
const element = (
<h2>Using {language}</h2>
);
Using JSX
If we want to, we can also have two different embedded expressions right next to each other, as shown below:
let language = 'JavaScript';
const element = (
<h2>Using {language}{'—a programming language'}</h2>
);
Using JavaScript—a programming language.
As the two expressions are next to each other, without any space in between, the rendered text also has no space in between 'JavaScript' and '—a programming language'.
Besides being used inside elements, {}
can also be used while setting values of attributes. We've already seen examples of these from previous chapters.
Consider the following code where the className
attribute's value is retrieved from a variable blueTextClassName
:
let blueTextClassName = 'text-blue';
const element = (
<h2 className={blueTextClassName}>JSX is splendid</h2>
);
Supposing that the CSS below has been set,
.text-blue {
color: blue
}
the output produced by this code would be as follows:
JSX is splendid.
Just basic stuff.
Now let's see more complex examples.
Suppose we have a variable isTextSmall
that tells us whether to apply a small font size to a given element. Based on this variable, we ought to additionally put a second class on a <p>
element, besides the .text
class, meant for small-sized text, .text--small
.
This can very easily be accomplished using JSX and the conditional operator in JavaScript, as demonstrated below:
let isTextSmall = true;
const element = (
<p className={'text ' + isTextSmall ? 'text--small' : ''}>JSX is splendid</p>
);
With the following CSS in place,
.text {
font-family: sans-serif;
font-size: 18px
}
.text--small {
font-size: 14px;
}
the output produced here is would be follows:
JSX is splendid
The conditional operator of JavaScript is really handy when we want to lay out conditional code inside JSX. We'll see it in more detail later on in this chapter.
Advancing forwards, there is a special expression that we could embed as an attribute of a given JSX element which serves to define a set of props, all at once. It's the called the spread attribute, and is denoted as ...
.
Suppose we have a divProps
object with us, as shown below, and want to use all of its properties as the props of a <div>
element:
let divProps = {
className: 'text-blue',
style: {
marginTop: 50
},
title: 'This is the title of the div.'
};
Using ...
we can conveniently do so as follows:
let divProps = {
className: 'text-blue',
style: {
marginTop: 50
},
title: 'This is the title of the div.'
};
const element = (
<div {...divProps}>This is a div.</div>
);
The JSX here gets converted to the following code:
const element = React.createElement('div', { ...divProps }, 'This is a div');
Notice how {...divProps}
in the JSX code becomes ...divProps
(using JavaScript's spread operator) in the props
argument to createElement()
.
This is how the spread attribute in JSX works.
Moving on, one thing that might confuse you while you're embedding JavaScript inside JSX is that when to and when not to use {}
to denote a JavaScript expression amid JSX code.
Do you find that intimidating?
Well, the idea is rudimentary:
{}
to denote a JavaScript expression wherever JSX is expected.If however, JavaScript itself is expected and we mistakenly provide curly braces, you can surely guess what'll happen — they'll denote an object literal and because the content inside the braces is syntactically invalid for an object literal, they'll likely lead to an error.
Values not rendered
React accepts many different kinds of values as a React node into the createElement()
function. However, only some are actually rendered out on to the document.
The values that don't get rendered are the Booleans, null
and undefined
.
There's a really good reason for not rendering either of these — so that conditional rendering could actually work, which we shall explore in the next section below.
Consider the following example where we try to render the value true
into the <h1>
element, yet we see nothing on the document:
const element = (
<h1>{true}</h1>
);
If we inspect the Developer Tools, we see that there indeed is our <h1>
rendered, but without any content inside it. That's because the value true
doesn't get rendered to the document.

We could try doing the exactly same thing with false
, null
and undefined
, and the result will remain the exact same.
If, however, we really want to display either of these four values out on the document, then we can simply convert them to a string before being rendered.
And example follows:
const element = (
<h1>{String(true)}</h1>
);
Simple, wasn't this?
Conditional rendering
As we render elements in React, it's quite often required to base this on some kind of a condition. If the condition matches, a given element might ought to be rendered, or else if the condition fails, we might or might not want to render another element.
This is effectively referred to as conditional rendering.
Now, we've heard that JSX is all about expressions, so obviously we can't possibly talk about if
, else
and switch
. Rather, we have to talk about expressions that aloow us to execute code conditionally. And for this, we have three really important JavaScript operators:
- The logical AND (
&&
) operator - The logical OR (
||
) operator - The ternary (
?:
) operator
If you're already aware of how to use these operators to directly execute a given piece of code, you are all set to proceed ahead. Otherwise, you could spare a few minutes and review them quickly before going on, as linked below.
&&
) and the logical OR (||
) operators in JavaScript Operators — Logical Operators. Learn more about the conditional operator (?:
) in JavaScript Conditions — The Conditional Operator (?:
).Here's how to use these operators for conditional rendering in React, starting with the logical AND (&&
) operator.
The logical AND (&&
) operator
Logical AND (&&
) is analogous to a single if
statement without a corresponding else
. When we want to render an element on the occasion when a condition is met, we should go for this operator.
Here's an example.
In the code below, we render an .info
<div>
only when the value of a variable info
is truthy, i.e. when it does hold some actual information.
const info = false;
const element = (
<section>
A section
{info && (
<div className="info">Information: {info}</div>
)}
</section>
);
In this case, since info
is false
, info && <div>
evaluates down to false
and then this value gets rendered. But we learnt just right above that React doesn't render false
, and so effectively, we get nothing rendered, which is precisely what we wanted.
Even if we inspect React's DevTools, we see that there's no <div>
inside the <section>
element above, which confirms that <div>
hasn't been rendered.
Let's change the value of info
and see the result then:
const info = 'Conditional rendering is amazing';
const element = (
<section>
A section
{info && (
<div className="info">Information: {info}</div>
)}
</section>
);
This time, because info
holds some information, the .info
element gets rendered out on to the document. Just as we desired.
As you shall discover in a later chapter, we'll actually be using this kind of a conditional render in one of our code snippets.
Now, let's talk about the logical OR (||
) operator.
The logical OR (||
) operator
The logical OR (||
) operator evaluates the left operand and if it's truthy, it returns it, or else returns the right operand. This is analogous to an if
statement with a negated condition, still without a corresponding else
.
Here's an example.
In the following code, we render some small description text description
inside a <p>
element. Since there's a chance that the description text is empty, we use the logical OR (||
) operator to specify a default description in case that does happen:
const description = '';
const element = (
<p>{description || 'No description available'}</p>
);
No description available
The value of description here was falsey (i.e. an empty string), and likewise we got the default description rendered. If we now change to a non-empty description, we'd get that rendered instead:
const description = 'This is a non-empty description.';
const element = (
<p>{description || 'No description available'}</p>
);
This is a non-empty description.
Super-duper amazing.
And now let's consider the third and last of the three operators used in conditional rendering: the ternary conditional operator (?:
).
The conditional (?:
) operator
There absolutely no guess work involved with the conditional operator (?:
) as there might be with the logical AND (&&
) and the logical OR (||
) operators. It's just an if
and else
kind-of operator.
When we have two different things to render, depending on the outcome of a condition, we should go for ?:
— hands-down.
In the following code, we extend the previous info
example to include a loading text when there's no info
to display:
const info = false;
const element = (
<section>
A section
{info ? (
<div className="info">Information: {info}</div>
) : (
<div>Loading...</div>
)}
</section>
);
As you shall explore later on, this is a really common pattern React applications, i.e. to render something to indicate loading while a given value doesn't get some information inside of it.
JSX comments
Since comments are denoted as follows in HTML:
<div>
<!-- This is an HTML comment -->
A simple div
</div>
and the fact that JSX resembles HTML, we might be tempted to think that JSX comments are denoted the same way.
Unfortunately, that's NOT the case.
A quick try can confirm this:
<div>
<!-- This is a JSX comment -->
A simple div
</div>
There's no native syntax for comments in JSX itself (and rightly so as we shall learn below). But this doesn't mean that we can't have comments in our JSX code.
Recall the pair of curly braces ({}
) used to denote an arbitrary JavaScript expression in JSX. Since {}
holds JavaScript, we can use a multi-line JavaScript comment inside it, and in this way, emulate a JSX comment.
Amazing, isn't it?
Here's an example of a comment in JSX:
<div>
{/* This is a JavaScript comment */}
A simple div
</div>
Now because the curly braces hold a JavaScript expression, we might as well be tempted to think that we could use single-line comments in there. And yes, we could, but not without taking some care.
If we denote a single-line comment in the same line as we have the curly braces, the comment would consume the entire line starting with //
. This means that the ending }
brace would become a part of the comment and, thus, leave the starting {
brace unmatched, ultimately leading to a syntax error.
Here's a demonstration:
<div>
{// This is a single-line JavaScript comment}
A simple div
</div>
The correct way to use a single-line comment is to, at the least, make sure that the closing }
brace comes at a new line.
Likewise, the following is correct:
<div>
{// This is a single-line JavaScript comment
}
A simple div
</div>
But almost no one would write a comment like this.
It's better to structure out the code as shown below:
<div>
{
// This is a single-line JavaScript comment
}
A simple div
</div>
In fact, no one would, or should, write a standalone JSX comment like this as well. It overcomplicates the embedded JavaScript expression.
The multi-line comment syntax is much better to use, as we don't have to worry about new lines and could easily remain consistent with it to denote any kind of a comment in JSX code — single-line and/or multi-line.
From this point onwards, we'll denote comments in JSX via {/* */}
.
JSX files
Using JSX is so common in the React community that there is a separate file extension to indicate the a file uses JSX. It's called .jsx, and a file with this extension is simply called a JSX file.
There's absolutely no difference in how we write code in a normal JavaScript file vs. in a JSX file — like literally no difference, at all. JSX files are only meant to help us quickly see which file contains JSX and which not just by seeing the file's extension.
Given two files to us, one with a .js extension and the other with a .jsx extension, without even looking at the code, we can quickly make a judgement that the second file, i.e. the .jsx one, is meant to hold React code.
But we can't claim this for the .js file. It may or may not contain React code; we can't be sure about it.
This lack of surety is actually helpful when organizing large code bases. That is, when we know that a file contains just JavaScript code, and not any JSX, we must give it a .js extension. Otherwise, given that the file contains JSX code, we must give it a .jsx extension.
Keep in mind that this is NOT a necessity. If you feel comfortable with .js, you can continue using it to hold JSX code.