JSX
JSX is a syntax extension for JavaScript that lets you write what looks like HTML inside your JavaScript code. React uses it to describe what the UI should look like.
Here is a simple example:
const element = <h1>Hello, world!</h1>;
That line is JSX. It is not a string and it is not actual HTML. It is JavaScript with a special syntax that React understands. Your build tool (Vite, Next.js, or similar) compiles it into regular JavaScript before it reaches the browser.
Why JSX Exists
Without JSX, you would have to write React.createElement() calls to build your UI:
// What you write without JSX
const element = React.createElement('h1', null, 'Hello, world!');
// What you write with JSX (compiles to the same thing)
const element = <h1>Hello, world!</h1>;
JSX is just a convenience. Both lines produce the same result. JSX is much easier to read, especially for complex nested structures.
The New JSX Transform
Since React 17, you no longer need to import React at the top of every file just to use JSX. Modern build tools handle this automatically:
// Old way (still works, but no longer required)
import React from 'react';
function Hello() {
return <h1>Hello</h1>;
}
// Modern way
function Hello() {
return <h1>Hello</h1>;
}
If you use Vite, Next.js, or Create React App (with React 17+), this is already configured for you. You only need to import React if you are using something from the React package directly, like useState or useEffect.
Embedding JavaScript Expressions
Use curly braces {} to embed any JavaScript expression inside JSX:
const name = 'Alice';
const element = <h1>Hello, {name}!</h1>;
const price = 9.99;
const element = <p>Price: ${price.toFixed(2)}</p>;
function double(x) {
return x * 2;
}
const element = <p>Double of 5 is {double(5)}</p>;
You can put any valid JavaScript expression inside the braces: variables, function calls, arithmetic, ternary operators. What you cannot put inside is a statement like an if block or a for loop. For conditionals, use a ternary or the && operator (see Conditional Rendering
).
Attributes in JSX
JSX attributes look like HTML attributes, with two important differences.
1. Use className instead of class
class is a reserved word in JavaScript, so JSX uses className:
// Wrong
<h1 class="title">Hello</h1>
// Correct
<h1 className="title">Hello</h1>
2. Use htmlFor instead of for
The for attribute on a <label> element becomes htmlFor in JSX:
// Correct
<label htmlFor="email">Email address</label>
<input id="email" type="email" />
3. Event handler names use camelCase
HTML events like onclick and onchange become onClick and onChange:
<button onClick={handleClick}>Click me</button>
4. Attribute values can be expressions
Wrap JavaScript expressions in curly braces (no quotes):
const imageUrl = '/logo.png';
const altText = 'Site logo';
const element = <img src={imageUrl} alt={altText} />;
Do not mix quotes and curly braces:
// Wrong: treats {imageUrl} as a literal string
<img src="{imageUrl}" />
// Correct
<img src={imageUrl} />
Self-Closing Tags
Any element without children must be self-closed with />:
<img src="/logo.png" alt="Logo" />
<input type="text" />
<br />
In HTML, <br> and <input> do not need closing tags. In JSX, they do. Forgetting the / is a common error.
Wrapping Multiple Elements
A JSX expression must have a single root element. If you need to return multiple elements, wrap them in a container:
// Wrong: two sibling elements with no wrapper
return (
<h1>Title</h1>
<p>Paragraph</p>
);
// One option: wrap in a div
return (
<div>
<h1>Title</h1>
<p>Paragraph</p>
</div>
);
The <div> wrapper adds an extra node to the DOM that you might not want. Use a Fragment instead:
Fragments
A Fragment lets you group elements without adding an extra DOM node:
import { Fragment } from 'react';
return (
<Fragment>
<h1>Title</h1>
<p>Paragraph</p>
</Fragment>
);
The short syntax <> and </> does the same thing and is more common:
return (
<>
<h1>Title</h1>
<p>Paragraph</p>
</>
);
Use Fragments when adding a wrapper <div> would break your layout, for example inside a table where the only valid children of <tbody> are <tr> elements.
Multiline JSX
When JSX spans multiple lines, wrap it in parentheses to avoid issues with JavaScript’s automatic semicolon insertion:
const element = (
<div>
<h1>Hello</h1>
<p>Welcome to my site.</p>
</div>
);
Common Mistakes
Using class instead of className
// Wrong
<div class="container">...</div>
// Correct
<div className="container">...</div>
Putting statements inside JSX
Curly braces accept expressions, not statements. if blocks and for loops are statements:
// Wrong
return (
<div>
{if (isLoggedIn) { <p>Welcome</p> }}
</div>
);
// Correct: use a ternary expression
return (
<div>
{isLoggedIn ? <p>Welcome</p> : <p>Please log in</p>}
</div>
);
Forgetting to close self-closing tags
// Wrong
<input type="text">
// Correct
<input type="text" />
Returning multiple elements without a wrapper
// Wrong
function MyComponent() {
return (
<h1>Title</h1>
<p>Text</p>
);
}
// Correct
function MyComponent() {
return (
<>
<h1>Title</h1>
<p>Text</p>
</>
);
}
See also