JSX
const jsx = <h1>This is JSX</h1>;
This funny tag syntax is neither a string nor HTML.
This is simple JSX code in React.
But the browser does not understand this JSX because it's not valid JavaScript code.
This is because we're assigning an HTML tag to a variable that is not a string but just
HTML code.
So to convert it to browser understandable JavaScript code, we use a tool
like Babel which is a JavaScript compiler/transpiler.
We can use the above JSX in our React code like this:
JSXDemo.js
import React from "react";
class JSXDemo extends React.Component {
render() {
return <h1>This is JSX</h1>;
}
}
export default JSXDemo;
App.js
import './App.css';
import JSXDemo from './JSXDemo';
function App() {
return (
<JSXDemo></JSXDemo>
);
}
export default App;
Output
When the Babel executes the above JSX, it converts it to the following code:
class JSXDemo extends React.Component {
render() {
return React.createElement("h1", null, "This is JSX");
}
}
This was the old way of writing code in React – but it's tedious to write
the React.createElement every time, even for adding a simple div.
So React introduced the JSX way of writing code which makes code easy to write
and understand.
What is the React.createElement Function?
Every JSX is converted to the React.createElement function call that the browser
understands.
The React.createElement has the following syntax:
React.createElement(type, [props], [...children])
Let’s look at the parameters of the createElement function.
type can be an HTML tag like h1, div or it can be a React component
props are the attributes you want the element to have
children contain other HTML tags or can be a component
The React.createElement call will also be converted to the object representation like
this:
{
type: 'h1',
props: {
children: 'This is JSX'
}
}
You can see this object representation if you assign the JSX to some local variable
and log it as shown below:
import React from "react";
class JSXDemo extends React.Component {
render() {
const jsx = <h1>This is JSX</h1>;
console.log(jsx);
return jsx;
}
}
export default JSXDemo;
You will see the log printed as shown below:
Now, take a look at the below code:
import React from "react";
class JSXDemo extends React.Component {
render() {
const jsx = <h1 id="jsx">This is JSX</h1>;
console.log(jsx);
return jsx;
}
}
export default JSXDemo;
Here, we've used the JSX like this:
<h1 id="jsx">This is JSX</h1>
So React, will convert this JSX to the below code:
React.createElement("h1", { id: "jsx" }, "This is JSX");
If there are any attributes added to the HTML tag as in our case, they will be passed
as the second parameter for the React.createElement call. The object representation
will look like this:
{
type: 'h1',
props: {
id: 'jsx',
children: 'This is JSX'
}
}
You will see the log printed as shown below:
So from all the above examples, it's clear that JSX is converted to
a React.createElement call and it's then converted to its object representation.
If you want to see the JSX to React.createElement conversion code, you can
navigate
https://babel-repl-clone.vercel.app/
There you can write JSX code on left and see the converted code on the right side
as shown below:
How to Return Complex JSX
Take a look at the below code:
import React from "react";
class JSXDemo extends React.Component {
render() {
return (
<p>This is first JSX Element!</p>
<p>This is another JSX Element</p>
);
}
}
export default JSXDemo;
Here, we're returning two paragraphs from the App component. But if you run the
code, you will get this error:
Reason
We're getting an error because React requires adjacent elements to be wrapped in a
parent tag.
As we have seen, <p>This is first JSX Element!</p> will be converted
to React.createElement("p", null, "This is first JSX Element!") and <p>This is another
JSX Element</p> will be converted to React.createElement("p", null, "This is another
JSX Element").
The converted code will look like this now:
import React from "react";
import ReactDOM from "react-dom";
const App = () => {
return (
React.createElement("p", null, "This is first JSX Element!");
React.createElement("p", null, "This is another JSX Element");
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Here we are returning two things from the App component which will not work
because there is no parent element to wrap both of them.
To make it work, the obvious solution is to wrap both of them in some parent
element, most probably a div like this:
import React from "react";
class JSXDemo extends React.Component {
render() {
return (
<div>
<p>This is first JSX Element!</p>
<p>This is another JSX Element</p>
</div>
);
}
}
export default JSXDemo;
Output
But there are also other ways of making it work.
First, you can try returning it as an array as shown below:
import React from "react";
class JSXDemo extends React.Component {
render() {
return (
[
<p>This is first JSX Element!</p>,
<p>This is another JSX Element</p>
]
);
}
}
export default JSXDemo;
This will get the job done, but as you can see in the browser console, you will get a
warning saying Warning: Each child in a list should have a unique "key" prop.
Because in React, every element in the array (when displayed using JSX) needs to
have a unique key added to it.
We can fix it by adding a unique key for the adjacent elements:
import React from "react";
class JSXDemo extends React.Component {
render() {
return (
[
<p key="first">This is first JSX Element!</p>,
<p key="second">This is another JSX Element</p>
]
);
}
}
export default JSXDemo;
The other way to fix it is by using the React.Fragment component:
import React from "react";
class JSXDemo extends React.Component {
render() {
return (
<React.Fragment>
<p key="first">This is first JSX Element!</p>
<p key="second">This is another JSX Element</p>
</React.Fragment>
);
}
}
export default JSXDemo;
React.Fragment was added in React version 16.2 because we always have to wrap
multiple adjacent elements in some tag (like div) inside every JSX returned by a
component. But that adds unnecessary div tags.
This is fine most of the time but there are certain cases where it's not fine.
For example, if we're using Flexbox, then there is a special parent-child relationship
in Flexbox's structure. And adding divs in the middle makes it hard to keep the
desired layout.
So using React.Fragment fixes this issue.
Fragments let you group a list of children without adding extra nodes to the DOM.
How to Add Comments to JSX Code
If you have a line of code like this:
<p>This is some text</p>
and you want to add a comment for that code, then you have to wrap that code in
JSX expresssion syntax inside the /* and */ comment symbols like this:
import React from "react";
class JSXDemo extends React.Component {
render() {
return (
<React.Fragment>
{/* <p>This is some text</p> */}
<p key="first">This is first JSX Element!</p>
<p key="second">This is another JSX Element</p>
</React.Fragment>
);
}
}
export default JSXDemo;
How to Add JavaScript Code in JSX
Up to this point, we have only used HTML tags as a part of JSX. But JSX becomes
more useful when we actually add JavaScript code inside it.
You can put any valid JavaScript expression inside the curly braces in JSX. For
example, 2 + 2, user.firstName, or formatName(user) are all valid JavaScript
expressions.
Calling Expression
import React from "react";
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}
const user = {
firstName: 'Harper',
lastName: 'Perez'
};
class JSXDemo extends React.Component {
render() {
return (
<h1>
Hello, {2+4}! </h1>
);
}
}
export default JSXDemo;
Calling JavaScript inbuilt Function
import React from "react";
const user = {
firstName: 'Harper',
lastName: 'Perez'
};
class JSXDemo extends React.Component {
render() {
return (
<h1>
Hello, {user.firstName.toUpperCase()} </h1>
);
}
}
export default JSXDemo;
Output
Calling User Defined JavaScript Function
import React from "react";
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}
const user = {
firstName: 'Harper',
lastName: 'Perez'
};
class JSXDemo extends React.Component {
render() {
return (
<h1>
Hello, {formatName(user)}! </h1>
);
}
}
export default JSXDemo;
We split JSX over multiple lines for readability. While it isn’t required, when doing
this, we also recommend wrapping it in parentheses to avoid the pitfalls of automatic
semicolon insertion.
JSX is an Expression Too
After compilation, JSX expressions become regular JavaScript
function calls and evaluate to JavaScript objects. This means that
you can use JSX inside of if statements and for loops, assign it to
variables, accept it as arguments, and return it from functions:
import React from "react";
function getGreeting(user) {
if (user.firstName=='Harper')
{
return <h1>Hello, {formatName(user)}!</h1>;
}
else
{
return <h1>Hello, Stranger.</h1>;
}
}
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}
const user = {
firstName: 'Harper',
lastName: 'Perez'
};
class JSXDemo extends React.Component {
render() {
return (
<div>{getGreeting(user)}</div>
);
}
}
export default JSXDemo;
Example
To add JavaScript code inside JSX, we need to write it in curly brackets like this:
import React from "react";
class JSXDemo extends React.Component {
render() {
const number=10;
return (
<p>Number: {number}</p>
);
}
}
export default JSXDemo;
Inside the curly brackets we can only write an expression that evaluates to some
value.So, often this syntax of using curly brackets is known as JSX Expression
Syntax.
Following are the valid things you can have in a JSX Expression:
A string like "hello"
A number like 10
An array like [1, 2, 4, 5]
An object property that will evaluate to some value
A function call that returns some value which may be JSX
A map method that always returns a new array
JSX itself
Following are the invalid things and cannot be used in a JSX Expression:
A for loop or while loop or any other loop
A variable declaration
A function declaration
An if condition
An object
We can write arrays in JSX Expressions because <p>{[1, 2, 3, 4]}</p> is finally
converted to <p>{1}{2}{3}{4}</p> when rendering (which can be rendered without
any issue).
In the case of an object, it’s not clear how the object should be displayed. For
example, should it be comma-separated key-value pairs or should it be displayed as
JSON? So you will get an error if you try to display the object in a JSX expression.
But we can use object properties instead.
Also note that undefined, null, and boolean are not displayed on the UI when used
inside JSX.
So if you have a boolean value and you want to display it on the UI you need to wrap
it in ES6 template literal syntax like this:
import React from "react";
class JSXDemo extends React.Component {
render() {
const isAdmin = true;
return (
<p>isAdmin is {`${isAdmin}`} </p>
);
}
}
export default JSXDemo;
Conditional Operators in JSX Expressions
We can’t write if conditions in JSX expressions, which you might think of as an issue.
But React allows us to write conditional operators, like ternary operators as well as
the logical short circuit && operator like this:
import React from "react";
class JSXDemo extends React.Component {
render() {
const a = 40;
const b=20;
return (
<p>{a > b ? "Greater" : "Smaller"}</p>
);
}
}
export default JSXDemo;
How to Nest JSX Expressions
You can even do nesting of JSX expressions like this:
import React from "react";
class JSXDemo extends React.Component {
render() {
const number = 10;
const b=20;
return (
<div>{
number > 0 ?
(<p>Number {number} is positive</p>) : (<p>Number
{number} is Negative</p>)
}
</div>
);
}
}
export default JSXDemo;
How to Add a Class in JSX
We can add attributes to the JSX elements, for example id and class, the same as in
HTML.
import React from "react";
class JSXDemo extends React.Component {
render() {
const id = "some-id";
return (
<div>
<h1 id={id}>This is a heading</h1>
<h2 className="active">This is another heading</h2>
</div>
);
}
}
export default JSXDemo;
Note that in React, we need to use className instead of class.
This is because if you use class instead of className, you will get a warning in the
console as shown below:
To understand why the warning is being shown, print the object representation of it
and you will see the following:
As you can see, the props object has the class property with a value active. But in
JavaScript, class is a reserved keyword so accessing props.class will result in an
error. This is why React decided to use className instead of class.
Note that in React, all the attribute names are written in camelCase.
Specifying Attributes with JSX
You may use quotes to specify string literals as attributes:
const element = <a href="https://www.reactjs.org"> link </a>;
You may also use curly braces to embed a JavaScript expression in
an attribute:
const element = <img src={user.avatarUrl}></img>;
Don’t put quotes around curly braces when embedding a JavaScript
expression in an attribute. You should either use quotes (for string
values) or curly braces (for expressions), but not both in the same
attribute.
Warning:
Since JSX is closer to JavaScript than to HTML, React DOM
uses camelCase property naming convention instead of HTML
attribute names.
For example, class becomes className in JSX,
and tabindex becomes tabIndex.
Label for becomes htmlFor
Specifying Children with JSX
If a tag is empty, you may close it immediately with />, like XML:
const element = <img src={user.avatarUrl} />;
JSX tags may contain children:
const element = (
<div>
<h1>Hello!</h1>
<h2>Good to see you here.</h2>
</div>
);
JSX Prevents Injection Attacks
It is safe to embed user input in JSX:
const title = response.potentiallyMaliciousInput;
// This is safe:
const element = <h1>{title}</h1>;
By default, React DOM escapes any values embedded in JSX before
rendering them. Thus it ensures that you can never inject anything
that’s not explicitly written in your application. Everything is
converted to a string before being rendered. This helps prevent XSS
(cross-site-scripting) attacks.