Command Palette

Search for a command to run...

Hectal
PHASE 1Beginner ~21 min· topic 3 of 7

Topic 1.3

JavaScript in JSX with Curly Braces

In one line

Curly braces { } open a window from JSX back into JavaScript: inside them you can put any expression (a variable, a calculation, a function call, a ternary, a template literal), as text or as an attribute value, but not a statement such as if or for.

Think of it like this

A greeting card with blanks: "Happy birthday, ____! You are ____ today." The card is printed once, and you fill the blanks for each friend. In JSX the tags are the printed card and curly braces are the blanks: <h1>Happy birthday, {name}!</h1>. Whatever JavaScript value you put in the blank is shown there.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

Curly braces
{ } in JSX: a spot where you write JavaScript instead of fixed text.
Expression
Code that produces a value: count, a + b, fn(), ok ? "yes" : "no".
Statement
Code that does something without producing a value: if, for, let x = 1. Not allowed in braces.
Ternary
The expression form of if/else: condition ? valueIfTrue : valueIfFalse.
Object literal
An object written directly in code: { color: "red" }. The inner pair in {{ }}.
Template literal
A string in backticks that can include values: ` Hi ${name} `.
Escaping
Turning special characters like < into safe text so they are shown, not run.
XSS
Cross-site scripting: an attack where someone's text gets run as code in your page. JSX braces prevent it.

Step by step

01Fixed text first

Start with a card where everything is typed in by hand. It works for one user only.

Profile.jsxwhole filejsx
<div className="profile">
  <h2>Asha Rao</h2>
  <p>1,250 pts</p>
</div>

02Open blanks with braces

Replace the fixed parts with expressions. The name is calculated, the points come from a function call. The output is the same, but now it follows the data.

Profile.jsxwhole filejsx
const fullName = user.first + " " + user.last;

<div className="profile">
  <h2>{fullName}</h2>
  <p>{formatPoints(user.points)}</p>
</div>

03Braces in attributes

Attributes take braces too. A number like width={48} stays a number. A template literal builds a string from pieces. No quotes around the braces.

Profile.jsxwhole filejsx
<img src={user.avatar} alt={`Photo of ${fullName}`} width={48} height={48} />

04Statements before the return, expressions inside

Need an if with several branches? Do it above the return and store the result in a variable. Inside the JSX, use the variable, or a ternary for a quick two-way choice.

Statements before the return, expressions insidediagram
Rendering diagram…

05Text is always text

If a value is a string containing <b>, React shows the characters. You'll see that in the second live example: the page shows the tags, and the HTML contains &lt;b&gt;.

Try it yourself

  1. 1

    Change the data, not the JSX

    In the profile example, change points to 400. Predict the three log lines before running. (400 pts · level 1, status plain, and the alt text is unchanged.)

  2. 2

    Choose the tag at run time

    In the forecast example, add const Heading = weather.temp > 30 ? "h1" : "h2"; above the return and use <Heading> … </Heading> instead of <h2>. The heading gets bigger on hot days.

  3. 3

    Try to inject HTML

    Change comment to "<img src=x onerror=alert(1)>". Predict: does anything pop up? No. React shows the characters as text, so the string can't run. This is why braces are safe.

Code & diagrams

Variables, calls, ternaries and template literals New tab

Every blank is an expression: a variable (`fullName`), a function call (`formatPoints`), arithmetic (`Math.floor(...) + 1`), template literals in attributes and a ternary for the label. Change `points` to `400` and watch the level, the label and the class follow.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

Photo of Asha Rao
1,250 pts · level 3
status gold
Statements before the return, and text that stays text New tab

The `if` lives above the `return`; inside the JSX there is only a variable and a ternary. The style uses double braces: JavaScript braces around an object. The comment's `<b>` is shown as characters: React escaped it to `&lt;b&gt;`.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

Visitor says: &lt;b&gt;Nice&lt;/b&gt; day!
Where braces can and can't gojsx
const url = "/logo.png";
const Tag = "h2";            // a tag chosen at run time: capitalised variable

<img src={url} />            // OK: attribute value
<p>{1 + 2}</p>               // OK: child (shows 3)
<Tag>Title</Tag>             // OK: renders <h2>
<Card {...props} />          // OK: spread all fields as attributes

<img src="{url}" />          // wrong: the literal text {url}
<{Tag}>Title</{Tag}>         // syntax error: braces can't be a tag name
<p>{if (ok) { "yes" }}</p>   // syntax error: if is a statement
<p>{ok ? "yes" : "no"}</p>   // OK: the expression form

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Put an if inside the braces

In the forecast example, replace <p>{advice}</p> with <p>{if (weather.temp > 30) { "Drink water" }}</p>.

terminal
$ Console
── what you'll see ──
Uncaught SyntaxError: Unexpected token, expected ";" (17:19)

Break #2

Quote the braces

In the profile example, change src={user.avatar} to src="{user.avatar}".

terminal
$ Preview
── what you'll see ──
A broken-image icon (with its alt text) instead of the blue circle. No warning in the console.

Myth vs fact

Myth

Double braces {{ }} are special JSX syntax.

Fact

They're two ordinary things: the JSX braces and an object literal inside them. style={{ color: "red" }} is the same as const s = { color: "red" }; style={s}.

Myth

You can't use if in React.

Fact

You can use any JavaScript in the component body. Only the inside of JSX braces is limited to expressions. Compute with if above the return.

Myth

Putting user text into JSX is dangerous.

Fact

JSX escapes strings, so user text is shown as text. The risks are dangerouslySetInnerHTML, javascript: URLs in href (React 19 blocks them) and other raw-HTML paths, covered in Phase 21.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    Because braces hold expressions, everything inside runs on every render. Keep it cheap: formatting a number is fine; filtering 10,000 items on each keystroke may not be (Phase 16 covers useMemo and the React Compiler).

  • ▸

    Avoid IIFEs ({(() => { if (...) return a; return b; })()}) inside JSX. They work, but extracting a variable or a small component is clearer and lets tools such as the React Compiler optimise it.

  • ▸

    Escaping happens in react-dom when it creates text nodes and sets attributes: text goes in through text-node APIs, never through HTML parsing. On the server, renderToString escapes <, >, &, " and ' in text and attributes for the same reason.

Remember this

  1. 1

    Inside JSX, anything between { and } is plain JavaScript, worked out every time the component renders. It must be an expression: code that produces a value. name, 2 + 3, user.first + " " + user.last, items.length, formatPrice(99), isOpen ? "Open" : "Closed" are all expressions. If you could write it on the right side of const x = …, it fits in braces.

  2. 2

    A statement is code that *does* something but doesn't produce a value: if, for, while, let x = 1, switch. Statements can't go inside braces, because the braces become an argument of a function call, and you can't pass an if as an argument. The fix is simple: do statement work **before the return** (compute variables with if), or use the expression versions inside JSX: the ternary a ? b : c instead of if/else, && for "show only if" (Topic 1.4) and map instead of for (Phase 3).

  3. 3

    Braces can go in exactly two places: as children (text content between tags, <p>{count}</p>) and as an attribute value (<img src={url} />). For an attribute, write either quotes for a fixed string (alt="Logo") or braces for a JavaScript value (alt={title}), never both: src="{url}" is the literal text {url}. Braces can't replace a tag name: to choose a tag at run time, store it in a capitalised variable (const Tag = level === 1 ? "h1" : "h2"; <Tag>…</Tag>). A third form, spread <Card {...props} />, passes every field of an object as an attribute (Phase 2).

  4. 4

    Double braces {{ }} are not special syntax. In style={{ color: "red" }} the outer pair means "JavaScript here" and the inner pair is an ordinary object literal. The same happens whenever you pass an object inline: <Chart options={{ animate: false }} />.

  5. 5

    Template literals (strings in backticks, ` Hello, ${name} ) are expressions too, handy for attributes built from pieces: alt={Photo of ${name}} or className={card ${active ? "active" : ""}}. Inside children you rarely need them, because Hello, {name}` already mixes text and values.

  6. 6

    Braces are safe by default. When you put a string in braces, React inserts it as text, escaping characters like < and &. A string such as "<b>Nice</b>" appears with its angle brackets visible; it never becomes HTML. This protects you from cross-site scripting (XSS: an attacker's text being run as code in your page). The only way to insert raw HTML is the deliberately scary prop dangerouslySetInnerHTML, covered with sanitising in Phase 21.

Explain it without notes

01

What can you put inside curly braces in JSX, and what can't you?

02

Where in JSX can curly braces appear?

03

Why does style={{ color: "red" }} have two pairs of braces?

04

Why is rendering a user's comment with {comment} safe?

Practice

01

Given const item = { name: "Pen", price: 20, qty: 3 }, render Pen × 3 = ₹60 using braces and a calculation.

02

Render a <p> whose class is "open" when const isOpen = true and "closed" otherwise, and whose text says We are open or Sorry, closed.

Trade-offs

  • ↔

    Long expressions inside JSX are hard to read. Move calculations into named variables above the return: the JSX then reads like the page it produces.

  • ↔

    Ternaries are great for two choices; chained ternaries for three or more get confusing. Use an if/switch above the return, or a lookup object (const icons = { sunny: "…", rainy: "…" }).

Done when you can

  • I can put variables, calculations and function calls in JSX with braces.

  • I can tell an expression from a statement.

  • I use braces or quotes for an attribute, never both.

  • I can explain double braces in style={{ }}.

  • I can build attribute strings with template literals.

  • I know JSX escapes text and why that matters.