Skip to main content

JSX

Expressions in JSX

Written by Published

Curly braces switch from markup back to JavaScript. Anything that produces a value is allowed; anything that does not is a syntax error.

Expressions, not statements

An expression produces a value: 2 + 2, user.name, items.map(...), a ternary. A statement does something: if, for, const. Only expressions go inside braces.

What fits in braces

jsx

function Demo() {
  const user = { name: "Ada", visits: 3 }
  const items = ["one", "two"]

  return (
    <div>
      <p>Maths: {2 + 2}</p>
      <p>Property: {user.name}</p>
      <p>Call: {user.name.toUpperCase()}</p>
      <p>Ternary: {user.visits > 1 ? "Returning" : "First time"}</p>
      <p>Template: {`${user.name} has ${user.visits} visits`}</p>
      <ul>{items.map((item) => <li key={item}>{item}</li>)}</ul>
    </div>
  )
}

const root = ReactDOM.createRoot(document.getElementById("root"))
root.render(<Demo />)

An if statement inside braces will not compile. Use a ternary inline, or compute the value above the return where statements are allowed.

What React actually renders

Strings and numbers render as text. Arrays render each item in turn. But several values render as nothing at all, silently, and that catches people out.

Values that disappear

jsx

function Falsy() {
  return (
    <div>
      <p>Zero renders: [{0}]</p>
      <p>Empty string renders nothing: [{""}]</p>
      <p>null renders nothing: [{null}]</p>
      <p>undefined renders nothing: [{undefined}]</p>
      <p>false renders nothing: [{false}]</p>
      <p>But an array renders each item: [{[1, 2, 3]}]</p>
    </div>
  )
}

const root = ReactDOM.createRoot(document.getElementById("root"))
root.render(<Falsy />)

Note the odd one out: zero renders. That is the source of a very common bug, where {items.length && <List />} puts a bare 0 on the page when the list is empty. The conditional rendering chapter deals with it properly.

Keep the logic above the return

Braces accept one expression, so a long ternary chain inside JSX quickly becomes unreadable. Anything past a simple condition belongs above the return, where you have the whole language available.

This is not only about tidiness. A variable computed above the return can be named, which turns {user.visits > 1 ? "Returning" : "First time"} into {greeting} - and the next person reads the name rather than re-deriving the condition.

Comments and whitespace

A comment inside JSX is an expression too: {/* like this */}. And JSX collapses whitespace between lines, so {" "} is how you force a space that would otherwise vanish.

  • Braces take one expression, not a block of statements.
  • Compute anything complicated above the return.
  • 0 renders; null, undefined, false and "" do not.
  • Objects cannot be rendered - React throws rather than guessing.