React JSX
Learning outcomes:
- What exactly is JSX
- JSX elements and attributes
- Embedding code inside JSX
- Values not rendered by React
- JSX comments
- Working with JSX files
Introduction
In the previous chapters, we got to know about JSX and even worked with it for a while but only in passing. Now, for this chapter, our aim is to go deep into this amazing supplemental innovation brought forward by the React team to help us build UIs with simplicity and intuition.
In particular, in this chapter, we shall understand what exactly is JSX and what it is not; JSX elements and attributes; how to embed code inside JSX using the {}
syntax; what are JSX files, with the .jsx extension; and a lot more.
What is JSX?
To start with, let's review what JSX is.
JSX 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 for React apps, per se. But it's so compact and rewarding over the createElement()
-call approach that when we talk about React, it's intrinsic to talk about 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 elements
JSX elements are simply syntactic sugar over creating React elements manually via createElement()
.
The syntax of creating JSX elements resembles that of creating HTML elements. That is, we have opening and closing tags denoted using angle brackets (<
and >
).
This makes really good sense because all UI libraries/frameworks, at the end of the day, create HTML elements, so why not use an HTML-like syntax for the UI if our code is to be used to create HTML elements anyway.
Now if we delve into the technical side, we see that a JSX element is a type of expression in JavaScript.
JSX elements are expressions in JavaScript
A JSX element is NOT a statement in JavaScript (unlike, for example, if
, while
, for
); it's purely an expression. Hence, wherever JavaScript expects an expression, we can indeed provide a JSX element there.
For example, we can assign a JSX element to a variable; pass it on to a function as an argument; set it as an attribute's vaue of another JSX element (which we'll see below); and so on. We'll see suchlike examples throughout this course.
This isn't hard to understand, for a JSX element boils down to a createElement()
call in code, and we of course know that createElement()
, being a function invocation, represents an expression.
This is precisely the syntax extension that JSX is — it extends JavaScript's expression grammar with another type, which is that of a JSX element.
React comes with a handful of predefined elements which are its abstractions over HTML DOM elements. And in JSX, they are represented just like they'd be in normal HTML source code.
For example, if we want to create an <h1>
element in React, 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>
See how close this feels to writing HTML. This approach to creating UI in React, by coding in an HTML-like syntax, starts to show its potential as soon as our UI concerns become complex, requiring intricate chains and trees of elements.
And not just this, but JSX elements can also be used to instantiate components in React. (We'll learn about components in way more detail in the upcoming chapter, React 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 a component using a JSX element 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 idea.
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.
Let's see an example.
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 inside it. This is because the content comes by virtue of the function greeting()
running (and returning), but in this case, the function doesn't get invoked.
<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! Why? Because it resolves to the following code,
const element = React.createElement(Greeting, null);
correctly referring to the Greeting()
function.
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.
Using this approach, 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. This follows exactly from how we denote void elements in HTML.
So, the <Greeting>
element shown above could be more compactly denoted as follows:
<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:
<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, without a /
inside it (just as we're used to doing in HTML sometimes) but get an error logged:
// The closing / is missing in the <img> tag.
<img src="image.png" alt="Some image">
The correct way to express this is as follows:
<img src="image.png" alt="Some image" />
The <img>
tag here includes the /
character at its end and, therefore, denotes 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.
/
character is not a new one; this exists in XML as well.JSX attributes
Since JSX elements mirror the syntax of HTML elements, it shouldn't be any surprising to know that we could set attributes on JSX elements too.
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()
call and, 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 that they're just props of the underlying element. So the way those props work is the same way the corresponding JSX attributes work.
As simple as that.
An important thing to remember is that, except for data-
and aria-
attributes, all JSX attributes are represented in the camel-case convention (which is simply because props in React follow this convention).
data-src
, aria-label
, accept-charset
, readonly
, and so on).For example,
- In HTML we have the
contenteditable
attribute, yet in JSX we have thecontentEditable
attribute (because we have acontentEditable
prop). - In HTML we have
readonly
, while in JSX we havereadOnly
(because we have areadOnly
in React). - In HTML, we have
accept-charset
, while in JSX we haveacceptCharset
(again, because we haveacceptCharset
in React).
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 different attribute naming 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.
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.
You can almost see where we're heading.
If we were to pass both these kinds of props to a component, this difference in the naming of the props (that is, some lowercased while some camel-cased) 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 this camel-cased prop naming convention in React.
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" />
);
The attribute is called data-src
, NOTdataSrc
.
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. 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 <p>
element or not. Based on this variable, we ought to set a class .text--sm
on the element, in addition to the .text
class.
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--sm' : ''}>JSX is splendid</p>
);
With the following CSS in place,
.text {
font-family: sans-serif;
font-size: 18px
}
.text--sm {
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 forward, there is a special expression that we could embed inside the starting tag of a JSX element to define a whole set of attributes to use at once; there's no need to one-by-one pass the attributes.
It's the called the spread attribute, and is denoted as {...props}
, where props
is an object containing all the props, i.e. attributes, to set on the JSX element.
Suppose we have a divProps
object with us, as shown below, and want to use all of its properties as the attributes (or simply 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
object provided to createElement()
.
The spread attribute carries a lot of potential in it. We can use it to pass an arbitrary set of attributes to a JSX element, which can then further pass those to another element down the chain, and so on.
However, this is kind of an advanced pattern in React which we won't be seeing until we cover other fundamental ideas in this course.
Anyways, 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 React nodes into the createElement()
function. However, only some are actually rendered out on to the document.
The values that don't get rendered are countless. It's easier to state the values that do get rendered in React, from which we can easily infer the ones that don't.
The values that get rendered in React are strings, numbers, arrays, and React elements; the rest are all void from rendering.
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.

We could try doing the exact same thing with false
, null
, undefined
, and just about any value apart from the four discussed above, and the result will remain the exact same.
But, let's say, if we wish to render either of these non-rendered values (such as undefined
, or true
), we can convert them to a string representation.
And example follows:
const element = (
<h1>{String(true)}</h1>
);
Simple, wasn't this?
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. 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 (.jsx extension)
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.
For example, 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, the .jsx one, holds React code.
But we can't claim this for the .js file. It may or may not contain React code; we just can't be sure about it.
This surety is helpful when organizing large code bases. That is, when a file's name ends with .jsx or .js (depending on whether it contains JSX code or not), we don't need to open it up and go through its contents in order to determine that it contains React code or purely JavaScript code — this is already apparent in the file extension.
Keep in mind that having JSX code in a JSX file is NOT a necessity. If you feel comfortable with .js, you can continue using it to hold JSX code.
Spread the word
Think that the content was awesome? Share it with your friends!
Join the community
Can't understand something related to the content? Get help from the community.