JSX Expressions in React: 7 Powerful Ways to Master {}

Topic 6 of 6

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.

Table of Contents

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 { }.

 

The Simple Rule
Think of { } as an “escape hatch” from JSX back to JavaScript. Anything inside the braces is evaluated as a JavaScript expression — and React renders whatever value it returns.

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
Objects Cause Errors:
Never put a plain JavaScript object directly in JSX: {"{{name: 'Rahat'}}"} will throw “Objects are not valid as a React child”. You must extract specific properties: {"{user.name}"}.

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}
Any declared variable, string, number, boolean, array, or object property.
2. Arithmetic
{price * qty}
Math operations, string concatenation, template literals.
3.Ternary
{x ? a : b}
Inline if-else. The only way to do conditionals directly in JSX.
4. Logical &&
{flag && <X/>}
Short-circuit evaluation. Renders right side only if left is truthy.
5. Function Calls
{fn(args)}
Call any function that returns a renderable value.
6. Array.map()
{arr.map(...)}
Transform arrays into lists of JSX elements.
7. Object Literals
style={{"{{}}"} color: 'red'}
Used for inline styles. Note the double {{ }} — outer is JSX, inner is object.
8. Template Literals
{`Hi ${name}`}
Embed variables inside strings with template literal syntax.

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
Define helper functions outside the component for formatting, status mapping, and complex logic. This keeps your JSX clean, readable, and testable. Only define them inside if they depend on component-specific state.

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
If you find yourself nesting ternaries 3+ levels deep, extract the logic into a function or variable before the return statement. It’s much more readable and maintainable.

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.

DO THIS
{count > 0 && (
  <p>{count} notifications</p>
)}

{isAdmin && <AdminPanel />}

{user?.name && (
  <p>Hello, {user.name}</p>
)}
AVOID THIS
{/* 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 && }"}
Renders the number0on screen, not nothing! This happens because 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
Every item rendered with .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 srcclassNamehrefstyle, 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>
)
Clean JSX
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 let variable using if/else before the return, 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:

  • false
  • null
  • undefined
  • true

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"}'}.