JSX Expressions in React: 7 Powerful Ways to Master {}
JSX Expressions in React
Everything you need to know about embedding JavaScript expressions inside JSX using curly braces from basic variables to function calls, ternaries, array maps, and advanced patterns. With real code examples, gotchas, and FAQs.
What Are JSX Expressions in React?
When you write React code, you use JSX a syntax that looks like HTML but lives inside JavaScript files. JSX is powerful, but by default, everything inside it is treated as markup, not code.
JSX expressions are the mechanism that lets you break out of markup mode and run real JavaScript. You do this by wrapping any valid JavaScript expression in curly braces { }.
Here’s the simplest possible example:
const name = "Rahat"
// Without { } — renders the literal text "name"
return <h1>Hello, name!</h1>
// Output: Hello, name!
// With { } — evaluates the variable
return <h1>Hello, {name}!</h1>
// Output: Hello, Rahat!
This is the fundamental power of JSX expressions. Without them, JSX would be just static markup. With them, your UI becomes dynamic, data-driven, and interactive.
How Curly Braces { } Work
When React’s build tool (Babel or the SWC compiler in Vite) compiles your JSX, it converts it into React.createElement() calls. Curly brace expressions become the children or prop values of those calls.
// What you write:
<h1>Hello, {name}!</h1>
// What Babel compiles it to:
React.createElement("h1", null, "Hello, ", name, "!")
The key insight: { } evaluates an expression and passes the result as a value to React.createElement(). React then knows how to render that value into the DOM.
What React Can Render
| Value Type | Renders As | Example |
|---|---|---|
| string | Text node | "Hello" → Hello |
| number | Text node | 42 → 42 |
| JSX element | DOM element | <span>Hi</span> |
| array of JSX | Multiple elements | [<li>A</li>, <li>B</li>] |
| null | Nothing (no error) | null → (empty) |
| undefined | Nothing (no error) | undefined → (empty) |
| false / true | Nothing (no error) | false → (empty) |
| object | Error! | Objects are not valid children |
8 Types of Valid JSX Expressions
Any valid JavaScript expression can go inside { }. Here’s a complete overview of all the types you’ll use in practice:
1. Variables
{name}
{price * qty}
{x ? a : b}
{flag && <X/>}
{fn(args)}
{arr.map(...)}
style={{"{{}}"} color: 'red'}
{`Hi ${name}`}
Embedding Variables in JSX
The most fundamental use of { } is rendering the value of a variable. Any JavaScript variable — string, number, array property, or computed value, can be placed directly in JSX.
const UserProfile = () => {
// Different variable types
const name = "Rahat Hussain"
const age = 22
const isAdmin = true
const tagline = `${name}'s Profile`
const user = { role: "Developer", city: "Lahore" }
return (
<div className="card">
<h1>{tagline}</h1> {/* Template literal */}
<p>Name: {name}</p> {/* String variable */}
<p>Age: {age}</p> {/* Number variable */}
<p>Next year: {age + 1}</p> {/* Arithmetic */}
<p>Role: {user.role}</p> {/* Object property */}
<p>City: {user.city}</p> {/* Object property */}
<p>ADMIN: {name.toUpperCase()}</p> {/* Method call */}
</div>
)
}
Calling Functions Inside JSX
You can call any function inside { } as long as it returns a value React can render. This is useful for formatting, computing values, and rendering complex sub-structures.
// Helper functions defined outside the component
const formatCurrency = (amount) =>
new Intl.NumberFormat("en-PK", { style: "currency", currency: "PKR" }).format(amount)
const formatDate = (date) =>
new Date(date).toLocaleDateString("en-PK", { year: "numeric", month: "long", day: "numeric" })
const getStatusBadge = (status) => {
const colors = { active: "green", pending: "orange", expired: "red" }
return <span style={{ color: colors[status] }}>{status}</span>
}
const Invoice = ({ invoice }) => (
<div>
<p>Amount: {formatCurrency(invoice.amount)}</p>
<p>Date: {formatDate(invoice.date)}</p>
<p>Status: {getStatusBadge(invoice.status)}</p>
<p>Tax: {formatCurrency(invoice.amount * 0.17)}</p>
</div>
)
Best Practice
Ternary Operator in JSX
The ternary operator condition ? valueIfTrue : valueIfFalse is the primary way to do inline conditional rendering in JSX. It’s an expression (not a statement), so it works perfectly inside { }.
const AuthButton = ({ isLoggedIn }) => (
<div>
{/* Render different text */}
<h2>{isLoggedIn ? "Welcome back!" : "Please sign in"}</h2>
{/* Render different components */}
{isLoggedIn
? <button className="btn-danger">Log Out</button>
: <button className="btn-primary">Log In</button>
}
{/* Dynamic className */}
<span className={isLoggedIn ? "badge-green" : "badge-red"}>
{isLoggedIn ? "Active" : "Inactive"}
</span>
{/* Nested ternary (use sparingly — hard to read) */}
<p>
Role: {isLoggedIn
? user.isAdmin ? "Admin" : "Member"
: "Guest"
}
</p>
</div>
)
Avoid Deeply Nested Ternaries
Logical && Operator
The && operator allows you to conditionally render an element only when a condition is truthy. If the condition is false, React renders nothing.
{count > 0 && (
<p>{count} notifications</p>
)}
{isAdmin && <AdminPanel />}
{user?.name && (
<p>Hello, {user.name}</p>
)}
{/* 0 renders as "0" on screen! */}
{count && <p>{count} items</p>}
{/* Fix: use explicit comparison */}
{count !== 0 && (
<p>{count} items</p>
)}
The Famous “0” Bug{"{0 && }"}
0 is falsy in JavaScript, but React still renders it because it’s a valid number. Always use {"{count !== 0 && ...}"} or {"{!!count && ...}"} to be safe.Rendering Arrays with .map()
Rendering a list of items from an array is one of the most common tasks in React. The .map() method transforms each array item into a JSX element. The result — an array of JSX — is a valid expression for { }.
const products = [
{ id: 1, name: "MacBook Pro", price: 450000, inStock: true },
{ id: 2, name: "iPhone 16", price: 280000, inStock: false },
{ id: 3, name: "AirPods Pro", price: 85000, inStock: true },
]
const ProductList = () => (
<ul className="product-list">
{products.map(product => (
<li
key={product.id} {/* ← REQUIRED: unique key */}
className={product.inStock ? "in-stock" : "out-of-stock"}
>
<strong>{product.name}</strong>
<span>PKR {product.price.toLocaleString()}</span>
{!product.inStock && <span>Out of Stock</span>}
</li>
))}
</ul>
)
{/* You can also chain .filter() before .map() */}
{products
.filter(p => p.inStock)
.map(p => <li key={p.id}>{p.name}</li>)
}
The key Prop is Mandatory
.map() needs a key prop. It must beuniqueamong siblings andstable(don’t use array index). React uses keys to efficiently identify which items changed, were added, or removed during re-renders.Expressions in JSX Attributes
Curly braces { } aren’t just for content between tags — they also power dynamic attribute values. This lets you set src, className, href, style, event handlers, and more dynamically.
const imgUrl = "/images/avatar.jpg"
const isActive = true
const userId = 42
const inputType = "email"
const handleClick = () => console.log("clicked")
return (
<div>
{/* src attribute */}
<img src={imgUrl} alt="User Avatar" />
{/* className — dynamic CSS class */}
<div className={isActive ? "tab active" : "tab"}>Dashboard</div>
{/* href with template literal */}
<a href={`/users/${userId}`}>View Profile</a>
{/* type from variable */}
<input type={inputType} />
{/* Boolean attribute */}
<button disabled={!isActive}>Submit</button>
{/* Event handler — function reference */}
<button onClick={handleClick}>Click Me</button>
{/* Inline style — double {{ }} */}
<p style={{ color: isActive ? "green" : "gray", fontWeight: "bold" }}>
Status
</p>
</div>
)
Object Expressions & Inline Styles
When you use inline styles in JSX, you use double curly braces {"{{"}{"}}"}. This can look confusing at first, but the logic is simple: the outer { } is the JSX expression, and the inner {{ }} is a regular JavaScript object literal.
{/* Double {{ }} explained: */}
{/* outer { } = JSX expression */}
{/* inner { } = JS object literal */}
<div style={{ backgroundColor: "#20232A", color: "#61DAFB" }}>
React box
</div>
{/* Better: define style object separately */}
const cardStyle = {
background: "white",
borderRadius: "12px", // camelCase! NOT border-radius
padding: "24px",
boxShadow: "0 4px 20px rgba(0,0,0,0.1)",
fontSize: "16px", // camelCase! NOT font-size
}
<div style={cardStyle}>Clean card</div>
{/* Dynamic styles using expressions */}
const progress = 75
<div style={{ width: `${progress}%`, height: "8px", background: "#61DAFB" }}/>
What You CANNOT Use in { }
JSX { } only accepts expressions — pieces of code that evaluate to a value. JavaScript statements (code that performs an action) are not allowed.
| Not Allowed (Statements) | Allowed Alternative (Expressions) | Why |
|---|---|---|
| if (x) { … } | x ? … : … | if is a statement |
| for (let i …) { } | array.map(…) | for is a statement |
| while (…) { } | Pre-compute outside JSX | while is a statement |
| switch (…) { } | Object map or function call | switch is a statement |
| const x = 5 | Declare above return | Declaration is a statement |
| { user } | {user.name} or JSON.stringify(user) | Objects not valid children |
const Component = ({ status, items }) => {
// ✅ Put if/else BEFORE return — results stored in variable
let statusLabel
if (status === "active") statusLabel = <span className="green">Active</span>
else if (status === "pending") statusLabel = <span className="yellow">Pending</span>
else statusLabel = <span className="red">Inactive</span>
// ✅ For loop alternative: use .map() directly
const listItems = items.map(item => (
<li key={item.id}>{item.name}</li>
))
return (
<div>
{statusLabel} {/* Use variable in JSX */}
<ul>{listItems}</ul>
</div>
)
}
Best Practices for JSX Expressions
1. Keep Logic Out of JSX
Complex logic belongs before the return statement — not embedded inside JSX. This makes your template clean and readable.
Messy JSX
return (
<div>
{users
.filter(u => u.age > 18)
.sort((a,b) => a.name.localeCompare(b.name))
.slice(0, 5)
.map(u => <p key={u.id}>{u.name}</p>)
}
</div>
)
const adults = users
.filter(u => u.age > 18)
.sort((a,b) => a.name.localeCompare(b.name))
.slice(0, 5)
return (
<div>
{adults.map(u =>
<p key={u.id}>{u.name}</p>
)}
</div>
)
2. Use Optional Chaining (?.) for Safe Access
// ❌ Crashes if user or address is null
<p>{user.address.city}</p>
// ✅ Optional chaining — safe, returns undefined if null
<p>{user?.address?.city}</p>
// ✅ With fallback using ?? (nullish coalescing)
<p>{user?.address?.city ?? "City not provided"}</p>
// ✅ Optional chaining on functions
<button onClick={props?.onPress ?? handleDefaultClick}>Click</button>
3. Extract Render Functions for Complex Sub-trees
const Dashboard = ({ user, stats }) => {
// Extract complex rendering into named functions
const renderHeader = () => (
<header>
<h1>Welcome, {user.name}</h1>
<p>Last login: {formatDate(user.lastLogin)}</p>
</header>
)
const renderStats = () => (
<section>
{stats.map(stat => (
<div key={stat.id} className="stat-card">
<h3>{stat.label}</h3>
<p>{stat.value}</p>
</div>
))}
</section>
)
return (
<div>
{renderHeader()} {/* Clean & readable! */}
{renderStats()}
</div>
)
}
Frequently Asked Questions
Why do we use curly braces { } in JSX?
JSX is a syntax extension that blends HTML-like markup with JavaScript. Inside JSX, everything is treated as markup by default. Curly braces { } act as an “escape hatch” — they tell React: “Stop treating this as markup and evaluate it as JavaScript instead.”
Without { }, React would render the literal text. With { }, React evaluates the expression and renders its return value. This is what makes React’s UI dynamic and data-driven.
Can you use if statements inside JSX { } expressions?
No. if is a JavaScript statement, not an expression. Statements don’t return values, so they can’t go inside JSX { }. Use these alternatives instead:
- Ternary operator:
{"{condition ? : }"} - Logical &&:
{"{condition && }"} - Variable before return: Assign JSX to a
letvariable usingif/elsebefore thereturn, then use the variable in JSX. - Helper function: Call a function inside
{ }that contains the if/else logic internally.
What does {{ }} mean in JSX? Why double curly braces?
Double curly braces {"{{}}"} in JSX are simply a JSX expression containing a JavaScript object literal. They are not special syntax:
- The outer
{ }is the JSX expression wrapper - The inner
{ }is a regular JavaScript object literal
You see this most commonly with inline styles: {"style={{ color: 'red', fontSize: '16px' }}"}. You could also write it as: {"const s = { color: 'red' }; then style={s}"} which shows it’s just a regular object in a curly brace.
What values does React NOT render in JSX expressions?
React intentionally renders nothing for these values — no DOM output, no error:
falsenullundefinedtrue
This is the mechanism that makes conditional rendering with && work: {"{isVisible && }"} — when isVisible is false, React renders nothing. However, the number 0 IS rendered (as “0” text) — this is a common gotcha with {"{count &&items}”} when count is 0.
How do you render a list with JSX expressions?
Use Array.map() inside curly braces. Map transforms each array item into a JSX element, producing an array of JSX — which React renders as multiple DOM nodes:
{`{items.map(item => (
{item.name} ))}`}
Critical rule:
Every element produced by .map() needs a key prop that is unique and stable use the item’s database ID, never the array index.
What is the difference between JSX expressions and JSX attributes?
Both use curly braces { } but in different positions:
- Content expression (between tags):
{variable}”} renders the value as text content or child elements{" - Attribute expression (as attribute value):
{''}sets the attribute to the dynamic value
For string attributes, you can also mix: {''}. One exception, you never use { } for string attribute literals: write {'alt="Photo"'} not {'alt={"Photo"}'}.
