Table of Contents
- What is JSX?
- Why Use JSX?
- Basic Syntax Rules of JSX
- Embedding Expressions in JSX
- JSX vs. HTML: Key Differences
- Attributes in JSX
- JSX and React Elements
- Conditional Rendering in JSX
- Looping in JSX
- JSX and Fragments
- Best Practices for Writing Clean JSX
- Conclusion
- References
What is JSX?
JSX is a syntax extension for JavaScript, designed to make writing React components more intuitive. It looks similar to HTML but is actually a way to describe what your React UI should look like.
Here’s a simple example of JSX:
const element = <h1>Hello, JSX!</h1>;
At first glance, this looks like HTML, but it’s not valid JavaScript. To run JSX in browsers, it must be transpiled (converted) into regular JavaScript. Tools like Babel handle this transpilation, converting JSX into React.createElement() calls (more on this later).
Note: If you use tools like Create React App, Vite, or Next.js, transpilation is set up automatically—no extra work needed!
Why Use JSX?
You might be thinking: “Can’t I just write React with plain JavaScript?” Yes, but JSX offers powerful benefits that make it worth learning:
1. Readability
JSX looks like HTML, which is familiar to most developers. Compare this JSX:
const greeting = <h1 className="welcome">Hello, React!</h1>;
to the equivalent plain JavaScript (using React.createElement):
const greeting = React.createElement(
"h1",
{ className: "welcome" },
"Hello, React!"
);
JSX is far easier to read and write, especially for complex UIs.
2. Declarative Syntax
JSX lets you describe what your UI should look like, not how to build it. For example, instead of manually updating the DOM, you write:
{isLoggedIn ? <WelcomeUser /> : <LoginButton />}
React handles rendering the correct component based on the isLoggedIn state.
3. Tight Integration with JavaScript
JSX eliminates the need for separate templating languages (e.g., Handlebars). You can embed JavaScript expressions directly in JSX using curly braces {}, making it easy to dynamically generate UI.
4. React’s Error Feedback
JSX helps React provide clearer error messages. If you forget a closing tag or misspell an attribute, React will flag it with a helpful warning.
Basic Syntax Rules of JSX
JSX may look like HTML, but it has strict syntax rules. Let’s break down the essentials:
1. Return a Single Root Element
JSX expressions must return a single root element. If you have multiple elements, wrap them in a parent (like a <div> or a fragment, covered later).
❌ Invalid (multiple roots):
// Error: Adjacent JSX elements must be wrapped in an enclosing tag
return (
<h1>Hello</h1>
<p>World</p>
);
✅ Valid (wrapped in a div):
return (
<div>
<h1>Hello</h1>
<p>World</p>
</div>
);
2. All Tags Must Close
Unlike HTML (where some tags like <br> or <img> can be unclosed), JSX requires explicit closing tags. Self-closing tags (e.g., <img>, <input>) must end with /.
❌ Invalid (unclosed tag):
<img src="logo.png"> // Error: Expected corresponding JSX closing tag for <img>
✅ Valid (self-closing):
<img src="logo.png" />
<br />
3. CamelCase for Most Identifiers
JSX uses camelCase for attribute names and event handlers, not kebab-case (HTML’s style). This aligns with JavaScript’s naming conventions (e.g., onclick in HTML becomes onClick in JSX).
Examples:
class→className(sinceclassis a reserved word in JavaScript)onclick→onClicktabindex→tabIndex
4. Expressions in Curly Braces {}
To embed dynamic values or JavaScript expressions in JSX, use curly braces {}. You can put variables, function calls, arithmetic, or even JSX inside them.
Embedding Expressions in JSX
One of JSX’s most powerful features is its ability to embed JavaScript expressions. Here are common use cases:
Variables
const name = "Alice";
const element = <h1>Hello, {name}!</h1>; // Renders: <h1>Hello, Alice!</h1>
Arithmetic
const element = <p>2 + 2 = {2 + 2}</p>; // Renders: <p>2 + 2 = 4</p>
Function Calls
function getGreeting(user) {
return user ? `Hello, ${user}!` : "Hello, Guest!";
}
const element = <h1>{getGreeting("Bob")}</h1>; // Renders: <h1>Hello, Bob!</h1>
Conditional Logic (Sneak Peek)
You can even embed conditionals (covered in detail later):
const isLoggedIn = true;
const element = <div>{isLoggedIn ? "Welcome back!" : "Please log in."}</div>;
JSX vs. HTML: Key Differences
While JSX resembles HTML, there are critical differences to avoid bugs. Here’s a cheat sheet:
| Feature | HTML | JSX |
|---|---|---|
| CSS class attribute | class="container" | className="container" |
| Label “for” attribute | <label for="name"> | <label htmlFor="name"> |
| Event handlers | onclick="handleClick()" | onClick={handleClick} |
| Self-closing tags | <img src="img.jpg"> | <img src="img.jpg" /> |
| Comments | <!-- This is a comment --> | {/* This is a comment */} |
| Boolean attributes | disabled (present = true) | disabled={true} (explicit) |
Example: HTML vs. JSX Button
HTML:
<button class="btn" onclick="alert('Hi')" disabled>Click Me</button>
JSX:
<button className="btn" onClick={() => alert('Hi')} disabled={true}>
Click Me
</button>
Attributes in JSX
JSX attributes can be static (fixed values) or dynamic (using expressions). Let’s explore common types:
1. Static Attributes
Use string literals for fixed values (enclosed in quotes):
<img src="logo.png" alt="React Logo" />
<a href="https://reactjs.org">React Docs</a>
2. Dynamic Attributes
For dynamic values (e.g., variables), use curly braces {}:
const imageUrl = "profile.jpg";
<img src={imageUrl} alt="Profile" /> // src uses the imageUrl variable
3. Style Attribute
To inline styles in JSX, pass a JavaScript object (not a string) with camelCase property names:
<div style={{ color: "blue", fontSize: "20px", padding: "10px" }}>
Styled text
</div>
- Outer braces: embed a JS expression.
- Inner braces: define the style object.
4. Boolean Attributes
In HTML, presence of an attribute (e.g., disabled, checked) implies true. In JSX, explicitly set boolean values:
// Disabled button (true)
<button disabled={true}>Can't Click</button>
// Enabled button (false)
<button disabled={false}>Click Me</button>
JSX and React Elements
Under the hood, JSX is syntactic sugar for React.createElement(), a function that creates React elements (plain objects representing DOM nodes).
For example, this JSX:
const element = <h1 className="greeting">Hello, World!</h1>;
is transpiled by Babel to:
const element = React.createElement(
"h1", // Type: HTML tag, component, or fragment
{ className: "greeting" }, // Props: attributes and children
"Hello, World!" // Children: text or other elements
);
React elements are lightweight descriptions of what the DOM should look like. React uses these elements to build and update the actual DOM efficiently (via the Virtual DOM).
Note: In React 17+, the
Reactimport is no longer required for JSX thanks to the new JSX transform. Babel now automatically imports the necessary functions.
Conditional Rendering in JSX
JSX doesn’t support if/else statements directly inside the template, but you can use these workarounds:
1. Ternary Operator
Inline conditionals with condition ? exprIfTrue : exprIfFalse:
const user = { name: "Alice", isAdmin: true };
return (
<div>
<h1>Welcome, {user.name}!</h1>
{user.isAdmin ? <AdminPanel /> : <UserPanel />}
</div>
);
2. Logical && Operator
Render content only if a condition is true:
const hasUnreadMessages = true;
return (
<div>
<h1>Inbox</h1>
{hasUnreadMessages && <p>You have unread messages!</p>}
</div>
);
If hasUnreadMessages is false, React ignores the expression.
3. Extracting Logic to Variables
For complex conditions, extract logic into a variable:
function UserGreeting({ user }) {
let greeting;
if (user) {
greeting = <h1>Hello, {user.name}!</h1>;
} else {
greeting = <h1>Hello, Guest!</h1>;
}
return <div>{greeting}</div>;
}
Looping in JSX
To render lists (e.g., arrays), use JavaScript’s map() method. Each item in the list should have a unique key prop (more on why later).
Example: Rendering a List of Names
const names = ["Alice", "Bob", "Charlie"];
const nameList = names.map((name, index) => (
// key helps React identify items during updates (use unique IDs in real apps)
<li key={index}>{name}</li>
));
return <ul>{nameList}</ul>;
Why key?
React uses key to track which items have changed, been added, or removed. Without keys, React may re-render the entire list unnecessarily, causing performance issues.
Best Practice: Use unique IDs (e.g., from a database) as keys instead of array indexes. Indexes work for static lists but can cause bugs in dynamic lists (e.g., when items are reordered).
JSX and Fragments
Earlier, we learned JSX needs a single root element. Wrapping elements in a <div> works, but it adds unnecessary nodes to the DOM (called “div soup”).
Fragments solve this! They let you group elements without adding extra DOM nodes.
Syntax:
- Long form:
<React.Fragment>...</React.Fragment> - Short form (most common):
<>...</>(no import needed in modern React).
Example:
Before (with div):
return (
<div> {/* Extra div in DOM */}
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</div>
);
After (with fragment):
return (
<> {/* No extra DOM node! */}
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</>
);
Best Practices for Writing Clean JSX
Writing maintainable JSX takes practice. Here are tips to keep your code clean:
1. Keep Components Small and Focused
A component should do one thing. Split large JSX into smaller components:
// Instead of:
function UserProfile() {
return (
<div>
<h1>John Doe</h1>
<p>Email: [email protected]</p>
<div className="posts">
{/* 50 lines of post rendering logic... */}
</div>
</div>
);
}
// Do:
function UserProfile() {
return (
<div>
<UserHeader name="John Doe" email="[email protected]" />
<UserPosts /> {/* Separate component for posts */}
</div>
);
}
2. Avoid Inline Logic
Extract complex expressions into variables or functions:
// Instead of:
<div>{user.isAdmin ? <AdminPanel permissions={user.permissions} /> : null}</div>
// Do:
const renderAdminPanel = () => {
if (user.isAdmin) {
return <AdminPanel permissions={user.permissions} />;
}
return null;
};
<div>{renderAdminPanel()}</div>;
3. Formatting Matters
Use consistent indentation (2 or 4 spaces) and line breaks for readability:
// Good:
<Button
className="primary"
onClick={handleSubmit}
disabled={isSubmitting}
>
Submit
</Button>
// Bad (hard to read):
<Button className="primary" onClick={handleSubmit} disabled={isSubmitting}>Submit</Button>
4. Use Fragments to Avoid Div Soup
As discussed earlier, prefer fragments over unnecessary <div> wrappers.
Conclusion
JSX is a powerful syntax extension that bridges the gap between HTML and JavaScript in React. By combining the readability of HTML with the flexibility of JavaScript, it makes building dynamic UIs intuitive and efficient.
Key takeaways:
- JSX is not HTML—it’s a syntax for describing React elements.
- Use curly braces
{}to embed JavaScript expressions. - Follow JSX-specific rules (camelCase, closing tags, fragments).
- Leverage
map()for lists and conditionals for dynamic UI.
With practice, writing JSX will feel second nature. Start small—build a simple component, experiment with expressions, and gradually tackle more complex UIs.