What is JSX?
JSX (JavaScript XML) is like a recipe written in a chef's shorthand - it looks familiar but has special powers. It's a syntax extension for JavaScript that lets you write HTML-like code directly in your JavaScript files.
JSX vs HTML: Key Differences
While JSX looks like HTML, it has some important differences. Think of JSX as HTML's smarter cousin:
1. ClassName Instead of Class
// HTML
<div class="container">Content</div>
// JSX
<div className="container">Content</div>
// Why? 'class' is a reserved word in JavaScript
2. CamelCase for Attributes
// HTML
<div onclick="handleClick()" tabindex="0">Click me</div>
// JSX
<div onClick={handleClick} tabIndex={0}>Click me</div>
// JSX uses camelCase for all attributes
3. Self-Closing Tags Must Close
// HTML (both work)
<img src="photo.jpg">
<br>
// JSX (must self-close)
<img src="photo.jpg" />
<br />
// Think of it as being more strict about closing tags
Embedding JavaScript in JSX
The real magic of JSX is embedding JavaScript expressions using curly braces {}. It's like adding dynamic ingredients to your recipe:
function Greeting() {
const name = "Sarah";
const hour = new Date().getHours();
// JavaScript expressions in curly braces
return (
<div>
<h1>Hello, {name}!</h1>
<p>It's {hour} o'clock.</p>
<p>2 + 2 = {2 + 2}</p>
<p>Today is {new Date().toLocaleDateString()}</p>
</div>
);
}
JSX is an Expression Too
JSX itself is an expression, which means you can use it in JavaScript logic:
function getGreeting(user) {
if (user) {
return <h1>Hello, {user.name}!</h1>;
}
return <h1>Hello, Stranger!</h1>;
}
// Using JSX in a ternary operator
const element = (
<div>
{isLoggedIn ? <UserDashboard /> : <LoginForm />}
</div>
);
// Assigning JSX to variables
const button = <button>Click me</button>;
const header = <h1>Welcome</h1>;
JSX Children
JSX elements can contain children, just like HTML. Think of it as nesting ingredients in a recipe:
// Single child
const element = <h1>Hello, world!</h1>;
// Multiple children
const container = (
<div>
<h1>Title</h1>
<p>Paragraph</p>
<button>Click me</button>
</div>
);
// Children can be JavaScript expressions
const list = (
<ul>
{[1, 2, 3].map(num => (
<li key={num}>Item {num}</li>
))}
</ul>
);
JSX Prevents Injection Attacks
JSX automatically escapes values to prevent XSS attacks. It's like having a food safety inspector for your code:
const userInput = '<script>alert("XSS!")</script>';
// This is safe - JSX escapes the content
const element = <div>{userInput}</div>;
// Renders as text, not executable code:
// <div><script>alert("XSS!")</script></div>
JSX Represents Objects
Under the hood, JSX creates React elements. It's like a recipe that gets converted to cooking instructions:
// This JSX:
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
// Is compiled to:
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
// Which creates this object:
const element = {
type: 'h1',
props: {
className: 'greeting',
children: 'Hello, world!'
}
};
JSX Style Attributes
Styles in JSX use JavaScript objects with camelCase properties:
// CSS styles as JavaScript objects
const divStyle = {
color: 'blue',
backgroundColor: 'lightgray',
padding: '10px',
borderRadius: '5px'
};
function StyledComponent() {
return (
<div style={divStyle}>
Styled with JavaScript object
</div>
);
}
// Inline styles
function InlineStyled() {
return (
<div style={{
color: 'red',
fontSize: '20px',
marginTop: '10px'
}}>
Inline styled text
</div>
);
}
Conditional Rendering in JSX
JSX supports various patterns for conditional rendering:
function ConditionalExample({ isLoggedIn, notifications }) {
return (
<div>
{/* Ternary operator */}
{isLoggedIn ? <LogoutButton /> : <LoginButton />}
{/* Logical AND operator */}
{notifications.length > 0 && (
<span>You have {notifications.length} notifications</span>
)}
{/* IIFE (Immediately Invoked Function Expression) */}
{(() => {
if (isLoggedIn) {
return <Dashboard />;
} else {
return <LandingPage />;
}
})()}
</div>
);
}
Lists and Keys in JSX
When rendering lists, each item needs a unique key. Think of keys as name tags at a party:
function TodoList({ todos }) {
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>
{todo.text}
</li>
))}
</ul>
);
}
// Keys help React identify which items have changed
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
JSX Fragments
Sometimes you need to return multiple elements without adding extra DOM nodes:
// Using Fragment (long syntax)
function FragmentExample() {
return (
<React.Fragment>
<h1>Title</h1>
<p>Paragraph</p>
</React.Fragment>
);
}
// Using Fragment (short syntax)
function ShortFragmentExample() {
return (
<>
<h1>Title</h1>
<p>Paragraph</p>
</>
);
}
// Fragments with keys
function KeyedFragments({ items }) {
return (
<dl>
{items.map(item => (
<React.Fragment key={item.id}>
<dt>{item.term}</dt>
<dd>{item.description}</dd>
</React.Fragment>
))}
</dl>
);
}
JSX Comments
Comments in JSX must be wrapped in curly braces:
function CommentExample() {
return (
<div>
{/* This is a JSX comment */}
<h1>Hello</h1>
{/*
Multi-line
JSX comment
*/}
{
// Single line comment inside braces
}
<p>Paragraph</p>
</div>
);
}
Common JSX Gotchas
1. Returning Multiple Elements
// ❌ Wrong - can't return multiple elements
function Wrong() {
return (
<h1>Title</h1>
<p>Paragraph</p>
);
}
// ✅ Correct - wrap in a parent element or fragment
function Correct() {
return (
<>
<h1>Title</h1>
<p>Paragraph</p>
</>
);
}
2. JavaScript Expressions Only
// ❌ Wrong - statements aren't allowed
function Wrong() {
return (
<div>
{if (true) { return "Yes" }}
</div>
);
}
// ✅ Correct - use expressions
function Correct() {
return (
<div>
{true ? "Yes" : "No"}
</div>
);
}
3. Objects as Children
// ❌ Wrong - objects can't be rendered directly
function Wrong() {
const user = { name: "John", age: 30 };
return <div>{user}</div>;
}
// ✅ Correct - render object properties
function Correct() {
const user = { name: "John", age: 30 };
return <div>{user.name}, {user.age}</div>;
}
JSX Best Practices
// Good JSX practices
function UserProfile({ user }) {
// Extract complex logic
const getStatusColor = (status) => {
switch(status) {
case 'active': return 'green';
case 'inactive': return 'gray';
case 'banned': return 'red';
default: return 'black';
}
};
// Use semantic HTML
return (
<article className="user-profile">
<header>
<h2>{user.name}</h2>
<span
className="status"
style={{ color: getStatusColor(user.status) }}
>
{user.status}
</span>
</header>
<section className="user-details">
<p>Email: {user.email}</p>
<p>Joined: {new Date(user.joinDate).toLocaleDateString()}</p>
</section>
</article>
);
}