Table of Contents
- What is JSX?
- How JSX Works Under the Hood
- Basic JSX Syntax Rules
- Embedding Expressions in JSX
- JSX Attributes and Props
- Conditional Rendering in JSX
- Rendering Lists with JSX
- JSX and Fragments
- JSX Best Practices
- Common JSX Pitfalls and How to Avoid Them
- Conclusion
- References
1. What is JSX?
At its core, JSX is a syntax extension for JavaScript that lets you write HTML-like code directly in your JavaScript files. It’s not HTML, nor is it a template language (like Handlebars or Pug). Instead, JSX is a declarative way to describe what your UI should look like, combining the power of JavaScript with the readability of HTML.
Example: JSX vs. Vanilla JavaScript
Without JSX, creating a React element requires using React.createElement, which can be verbose:
// Without JSX
const element = React.createElement(
"h1",
{ className: "greeting" },
"Hello, React!"
);
With JSX, the same element becomes concise and readable:
// With JSX
const element = <h1 className="greeting">Hello, React!</h1>;
Why React Uses JSX?
- Readability: JSX looks like HTML, making it easier to visualize the UI structure.
- Productivity: Reduces boilerplate code compared to
React.createElement. - Integration with JavaScript: Seamlessly embeds JavaScript logic (variables, expressions, etc.) directly into the UI.
2. How JSX Works Under the Hood
Browsers don’t understand JSX natively. So, how does it work?
Transpilation with Babel
JSX is transpiled (converted) into regular JavaScript before it reaches the browser. The most common tool for this is Babel, a JavaScript compiler. Babel converts JSX into React.createElement calls, which React then uses to create virtual DOM elements.
The Role of React.createElement
React.createElement is a function that creates React elements (plain JavaScript objects representing DOM nodes). Its syntax is:
React.createElement(type, [props], [...children]);
type: The element type (e.g.,"h1", a component likeUser).props: An object of attributes (e.g.,{ className: "greeting" }).children: Nested elements or text (e.g.,"Hello, React!").
Example: JSX → React.createElement
Consider this JSX:
const element = <h1 className="greeting">Hello, {name}!</h1>;
Babel transpiles it to:
const element = React.createElement(
"h1",
{ className: "greeting" },
"Hello, ",
name,
"!"
);
React then converts this element object into a virtual DOM node, which is eventually rendered to the actual DOM.
3. Basic JSX Syntax Rules
JSX looks like HTML, but it has stricter rules. Let’s break down the essentials:
1. Element Structure
All JSX elements must be properly closed. Self-closing tags (e.g., <img>, <input>) require a trailing slash:
// ✅ Correct: Self-closing tag
<img src="logo.png" alt="React Logo" />
// ❌ Incorrect: Unclosed tag
<img src="logo.png" alt="React Logo">
2. className Instead of class
In HTML, we use class to define CSS classes. In JSX, use className instead (because class is a reserved keyword in JavaScript):
// ✅ Correct
<div className="container">Hello</div>
// ❌ Incorrect
<div class="container">Hello</div>
3. htmlFor Instead of for
Similarly, for (used with labels) is a reserved keyword, so JSX uses htmlFor:
// ✅ Correct
<label htmlFor="username">Username:</label>
<input type="text" id="username" />
// ❌ Incorrect
<label for="username">Username:</label>
4. Wrap Multiple Elements
A JSX expression can only return one root element. If you need to return multiple elements, wrap them in a parent (e.g., a <div>, a fragment, or <></>):
// ✅ Correct: Wrapped in a div
const App = () => (
<div>
<h1>Welcome</h1>
<p>Hello, React!</p>
</div>
);
// ✅ Correct: Wrapped in a fragment (no extra div)
const App = () => (
<>
<h1>Welcome</h1>
<p>Hello, React!</p>
</>
);
// ❌ Incorrect: Multiple root elements
const App = () => (
<h1>Welcome</h1>
<p>Hello, React!</p>
);
5. Expressions in Curly Braces {}
To embed JavaScript expressions in JSX, wrap them in curly braces {}. This includes variables, function calls, arithmetic, and more:
const name = "Alice";
const age = 30;
const element = (
<div>
<p>Name: {name}</p>
<p>Age next year: {age + 1}</p>
<p>Greeting: {getGreeting(name)}</p>
</div>
);
6. Comments in JSX
Comments in JSX must be wrapped in curly braces and use /* */ syntax:
const element = (
<div>
{/* This is a JSX comment */}
<h1>Hello</h1>
</div>
);
7. CamelCase for Attributes
JSX attributes use camelCase (not kebab-case) for consistency with JavaScript. For example:
onclick→onClicktabindex→tabIndexbackground-color→backgroundColor(for inline styles)
4. Embedding Expressions in JSX
JSX’s power lies in its ability to mix JavaScript logic with UI. Here are common ways to embed expressions:
Variables
const user = { name: "Bob", age: 25 };
const element = <p>User: {user.name}, Age: {user.age}</p>;
Function Calls
function formatName(user) {
return `${user.firstName} ${user.lastName}`;
}
const user = { firstName: "John", lastName: "Doe" };
const element = <h1>Hello, {formatName(user)}!</h1>;
Arithmetic and Operations
const price = 10;
const tax = 0.2;
const element = <p>Total: ${price * (1 + tax)}</p>; // Renders "Total: $12"
Ternary Operators (Conditional Logic)
Use ternary operators for inline conditionals:
const isLoggedIn = true;
const element = <p>{isLoggedIn ? "Welcome back!" : "Please log in"}</p>;
5. JSX Attributes and Props
In JSX, attributes (called “props” in React) pass data to components. Here’s how to use them:
HTML Attributes vs. React Props
Most HTML attributes map directly to React props, but with camelCase (e.g., onclick → onClick). Some props are unique to React (e.g., key, ref).
Inline Styles
To add inline styles in JSX, pass a JavaScript object (not a string) to the style prop. Use camelCase for CSS properties:
const style = {
color: "blue",
fontSize: "20px", // "font-size" in CSS → "fontSize" in JSX
marginTop: "10px"
};
const element = <p style={style}>Styled text</p>;
Passing Props to Components
When using custom components, pass props like HTML attributes:
// Define a component
function UserCard(props) {
return (
<div className="card">
<h2>{props.name}</h2>
<p>Email: {props.email}</p>
</div>
);
}
// Use the component with props
const element = <UserCard name="Alice" email="[email protected]" />;
6. Conditional Rendering in JSX
JSX doesn’t support if-else statements directly, but there are several ways to render conditionally:
1. Ternary Operator
const isAdmin = true;
const element = (
<div>
{isAdmin ? (
<button>Delete User</button>
) : (
<p>You are not an admin</p>
)}
</div>
);
2. Logical && Operator
Render content only if a condition is true:
const hasUnreadMessages = true;
const element = (
<div>
<h1>Inbox</h1>
{hasUnreadMessages && <p>You have unread messages!</p>}
</div>
);
3. Early Returns
For complex conditionals, use early returns in the component function:
function Greeting(props) {
if (!props.isLoggedIn) {
return <p>Please log in.</p>; // Early return
}
return <p>Welcome back, {props.user}!</p>;
}
7. Rendering Lists with JSX
To render arrays of data, use the map() method to transform the array into JSX elements. Always include a key prop to help React identify list items efficiently.
Example: Rendering a List
const todos = [
{ id: 1, text: "Learn JSX" },
{ id: 2, text: "Build a component" },
{ id: 3, text: "Deploy app" }
];
function TodoList() {
return (
<ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
);
}
The key Prop
keyis a special prop that helps React track which items have changed, been added, or removed.- Always use unique, stable values for
key(e.g., IDs from your data). Avoid using indexes unless the list is static (no reordering/additions).
8. JSX and Fragments
When returning multiple elements from a component, wrapping them in a <div> can add unnecessary nodes to the DOM. Fragments solve this by letting you group elements without a wrapper.
Syntax
- Long form:
<React.Fragment> - Shorthand:
<></>(most common)
Example
// Without fragments (adds an extra div)
function UserProfile() {
return (
<div>
<h1>John Doe</h1>
<p>Email: [email protected]</p>
</div>
);
}
// With fragments (no extra div)
function UserProfile() {
return (
<>
<h1>John Doe</h1>
<p>Email: [email protected]</p>
</>
);
}
Fragments are especially useful in lists, tables, and grids where extra wrappers can break CSS or layout.
9. JSX Best Practices
1. Keep JSX Clean and Readable
- Break long JSX into multiple lines (use parentheses for multi-line JSX).
- Indent nested elements for clarity.
2. Avoid Inline Styles for Complex Styling
Use CSS classes (via className) instead of inline styles for large apps. Inline styles are best for dynamic, component-specific styles.
3. Use Fragments to Reduce DOM Clutter
Avoid unnecessary <div> wrappers—use <></> instead.
4. Always Use key in Lists
Never omit the key prop when rendering lists with map().
5. Extract Logic to Variables/Helper Functions
Keep JSX focused on UI by moving complex logic to variables or helper functions:
// ❌ Not ideal: Complex logic in JSX
const element = (
<div>
{users.map(user => (
<User
key={user.id}
name={user.name}
isAdmin={user.roles.includes('admin') ? true : false}
/>
))}
</div>
);
// ✅ Better: Extract logic to a variable
const isAdmin = (user) => user.roles.includes('admin');
const element = (
<div>
{users.map(user => (
<User key={user.id} name={user.name} isAdmin={isAdmin(user)} />
))}
</div>
);
10. Common JSX Pitfalls and How to Avoid Them
1. Forgetting to Close Tags
JSX requires all tags to be closed (e.g., <img> → <img />).
2. Using class Instead of className
Remember: class is reserved in JavaScript—use className for CSS classes.
3. Not Wrapping Multiple Elements
Always wrap multiple JSX elements in a fragment or parent tag.
4. Using if-else Inside JSX
JSX doesn’t support if-else blocks. Use ternary operators, &&, or early returns instead.
5. Ignoring the key Prop in Lists
Missing key props can cause bugs in list rendering (e.g., incorrect updates).
11. Conclusion
JSX is more than just “HTML in JavaScript”—it’s a powerful syntax that bridges the gap between logic and UI in React. By understanding how JSX works (via React.createElement), mastering its syntax rules, and following best practices, you’ll write cleaner, more maintainable React code.
Whether you’re rendering simple text, conditionally displaying content, or building complex lists, JSX makes describing your UI intuitive and efficient. It truly is the heartbeat of React, enabling developers to create dynamic, interactive interfaces with ease.