Embedding Expressions
JSX would be little more than static markup without a way to mix in dynamic data. Curly braces ({ }) are that escape hatch: they drop you out of markup and back into plain JavaScript, letting you embed any value or expression directly inside your UI. Mastering what does and does not belong inside those braces is the single most important JSX skill, because it shapes how you render data, format text, and wire up styles.
The curly-brace escape
Anywhere inside JSX—between tags or inside an attribute value—a pair of curly braces switches the parser from “markup mode” into “JavaScript mode.” Whatever you put inside is evaluated, and its result is rendered.
function Greeting() {
const name = "Ada";
const hour = new Date().getHours();
return <h1>Good {hour < 12 ? "morning" : "day"}, {name}!</h1>;
}
You can reference variables, do math, index into arrays, read object properties, and call functions—anything that produces a value.
Expressions, not statements
This is the rule that trips up newcomers: only expressions are allowed in { }, never statements. An expression evaluates to a value; a statement performs an action and returns nothing. So if, for, while, and switch are forbidden inline, while ternaries, logical operators, and function calls are welcome.
// Works — every line is an expression
<p>{2 + 2}</p>
<p>{user.firstName.toUpperCase()}</p>
<p>{items.length > 0 ? "Has items" : "Empty"}</p>
<p>{prices.reduce((sum, p) => sum + p, 0)}</p>
// Breaks — these are statements, not expressions
<p>{if (loggedIn) { "Hi" }}</p> // SyntaxError
<p>{for (let i = 0; i < 3; i++) {}}</p> // SyntaxError
When you need branching or loops, compute the value above the
returnand embed the resulting variable, or use a ternary /.map()inline. The JSX itself stays a flat tree of expressions.
Rendering numbers and strings
Strings and numbers render exactly as you’d expect—their text representation is inserted into the DOM.
function Receipt() {
const item = "Coffee";
const price = 4.5;
const qty = 3;
return (
<p>
{qty} × {item} = ${(price * qty).toFixed(2)}
</p>
);
}
Output:
3 × Coffee = $13.50
Note that whitespace and adjacent text are preserved, so you can interleave literal text with { } blocks freely.
Values React ignores
React deliberately renders nothing for null, undefined, false, and true. This is what makes conditional rendering with && work: when a condition is falsy, the expression yields false and React skips it.
function Notice({ message }) {
return (
<div>
{message && <p className="alert">{message}</p>}
{null}
{undefined}
{false}
</div>
);
}
If message is empty, only an empty <div> is rendered. The following table summarizes how each value type is treated:
Value in { } | Rendered output |
|---|---|
"hello" (string) | hello |
42 (number) | 42 |
0 (number) | 0 — renders, watch this! |
null | nothing |
undefined | nothing |
true / false | nothing |
| array of elements | each element, concatenated |
The number
0is a real gotcha.{count && <Badge />}renders the literal0whencountis0, because0 && xevaluates to0. Guard with{count > 0 && <Badge />}instead.
Calling functions
Because a function call is an expression, you can invoke helpers inline to format or derive data. Keep these calls cheap—they run on every render.
function formatDate(iso) {
return new Intl.DateTimeFormat("en-US", { dateStyle: "medium" }).format(
new Date(iso),
);
}
function Post({ title, publishedAt }) {
return (
<article>
<h2>{title}</h2>
<time>{formatDate(publishedAt)}</time>
</article>
);
}
Output:
Jun 14, 2026
For anything more involved, compute the value in a const above the return so the JSX stays readable.
Inline objects for style
Most attributes take a single value, but style is special: it expects a JavaScript object whose keys are camelCased CSS properties. That means you’ll see two sets of braces—the outer pair enters JavaScript, the inner pair is the object literal.
function ProgressBar({ percent }) {
return (
<div style={{ background: "#eee", borderRadius: 8 }}>
<div
style={{
width: `${percent}%`,
height: 12,
background: percent > 80 ? "#16a34a" : "#2563eb",
transition: "width 200ms",
}}
/>
</div>
);
}
Numeric values like 12 are treated as pixels for length properties. For static styles, prefer CSS classes via className; reserve inline style objects for values that genuinely depend on state or props.
Best Practices
- Put only expressions in
{ }—moveif/forlogic above thereturnand embed the result. - Format and derive data in named variables when the expression grows beyond a glance.
- Guard
&&against falsy non-booleans like0and""to avoid accidentally rendering them. - Remember
null,undefined, and booleans render nothing—use them intentionally for conditional UI. - Keep inline function calls inexpensive; they execute on every render.
- Use inline
styleobjects only for dynamic values; reach forclassNamefor everything static.