Conditional Rendering
Reviewed & published by Brayan K
Conditional rendering means deciding what UI to show based on a condition. Because JSX is just an expression, you use ordinary JavaScript: the ternary cond ? a : b to pick between two things, the && operator to show something only when true, and a plain variable / early return when you have several cases.
Part of the free React course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.
What You'll Learn
- Use a ternary to choose between two pieces of UI
- Use && to show something only when a condition is true
- Avoid the '0 leaks onto the screen' && trap
- Handle many cases with a variable or early return
- Why you can't put if directly inside JSX braces
- Pick the cleanest tool for 1, 2, or many branches
1️⃣ The Ternary — Pick One of Two
When you're choosing between exactly two things to render, reach for the ternary condition ? a : b. It's an expression, so it drops straight into JSX braces.
function Profile({ isLoggedIn }) {
return (
<div>
{isLoggedIn ? <Dashboard /> : <LoginButton />}
</div>
);
}// TERNARY: condition ? whenTrue : whenFalse — choose one of two.
function greeting(isLoggedIn) {
return isLoggedIn ? "Welcome back!" : "Please log in";
}
console.log(greeting(true)); // Welcome back!
console.log(greeting(false)); // Please log in
// In JSX: {isLoggedIn ? <Dashboard /> : <LoginButton />}2️⃣ The && Operator — Show or Show Nothing
When you want to show something only if a condition holds (and nothing otherwise), use cond && element. If the condition is false, React renders nothing. The classic bug: a number like 0 is falsy, so {count && <X/>} renders a literal 0. Always test a boolean: {count > 0 && <X/>}.
function Inbox({ unread }) {
return (
<div>
{unread > 0 && <Badge count={unread} />}
</div>
);
}// && : show something ONLY when the condition is true.
// If the left side is false, React renders nothing.
function badge(unread) {
return unread > 0 && (unread + " new"); // false OR the string
}
console.log(badge(3)); // 3 new
console.log(badge(0)); // false -> in React this renders NOTHING
// ⚠️ The trap: {count && <X/>} renders a literal 0 when count is 0.
// Always use a boolean test: count > 0 && <X/>
console.log(0 && "shown?"); // 0 <- React would print this 0!
console.log(0 > 0 && "shown?"); // false <- correct, renders nothingYour turn — use a ternary and a safe &&:
// 🎯 YOUR TURN — fill in each ___ then press "Try it Yourself".
// 1) Use a TERNARY to return "On" when power is true, else "Off".
// 2) Use && to return the cartCount only when it is greater than 0.
function powerLabel(power) {
return power ___ "On" ___ "Off"; // 👉 ? ... :
}
function cartBadge(cartCount) {
return cartCount ___ 0 && cartCount; // 👉 use > so 0 renders nothing
}
console.log(powerLabel(true)); // On
console.log(powerLabel(false)); // Off
console.log(cartBadge(5)); // 5
console.log(cartBadge(0)); // false
// ✅ Expected output:
// On
// Off
// 5
// false3️⃣ Many Cases — Variables & Early Returns
You can't put an if statement inside JSX braces (braces hold expressions, and if is a statement). For three or more branches, compute the element in a variable above the return, or use early returns — one per case. Far cleaner than nested ternaries.
function Status({ status }) {
if (status === "loading") return <Spinner />;
if (status === "error") return <ErrorBox />;
if (status === "empty") return <EmptyState />;
return <Results />; // the default case
}// MANY CASES: compute the UI above the return, then use the variable.
function statusLabel(status) {
let label;
if (status === "loading") label = "⏳ Loading";
else if (status === "error") label = "❌ Error";
else if (status === "empty") label = "📭 Nothing here";
else label = "✅ Ready";
return label; // in JSX you'd put {label} or return <p>{label}</p>
}
console.log(statusLabel("loading")); // ⏳ Loading
console.log(statusLabel("error")); // ❌ Error
console.log(statusLabel("empty")); // 📭 Nothing here
console.log(statusLabel("ok")); // ✅ Ready🧩 Reorder Challenge
These lines build a component that handles three states with early returns. Put them in the right order:
A. if (error) return <p>Error</p>;
B. function View({ loading, error }) {
C. return <p>Ready</p>;
D. if (loading) return <p>Loading</p>;
E. }Common Errors (and the fix)
- A stray 0 on screen. — You wrote {count && <X/>}. Use {count > 0 && <X/>}.
- "Unexpected token" putting if in JSX. — Move the if above the return and use a variable, or use a ternary inside the braces.
- Nothing renders for the "false" branch and you wanted a fallback. — && shows nothing when false; switch to a ternary with an explicit else.
- Unreadable nested ternaries. — Three or more cases? Use early returns or a lookup object instead.
📋 Quick Reference
| Situation | Tool |
|---|---|
| One of two things | {ok ? <Yes /> : <No />} |
| Show only if true | {count > 0 && <Badge />} |
| Hide a number-0 leak | {count > 0 && ...} |
| Many cases | if (x) return <A />; ... |
🧠 Quick Recall
1. What does {0 && <Badge/>} render?
A literal 0 on screen. 0 is falsy so && returns 0, and React renders it. Use count > 0 &&.
2. You need to show a spinner OR the content — which tool?
A ternary: {loading ? <Spinner/> : <Content/>} — two branches, pick one.
3. Can you write {if (x) ...} inside JSX?
No. Braces hold expressions; if is a statement. Compute above the return or use a ternary.
Mini-Challenge: Notification Line
Build one display string per user combining a status dot, the name, and an unread count that only appears when greater than 0. Run it and check your output.
// 🎯 MINI-CHALLENGE: a notification line
//
// Given a user object, build ONE display string:
// 1. If user.isOnline, start with "🟢 ", else "⚫ ".
// 2. Add the user.name.
// 3. If user.unread > 0, append " (" + user.unread + ")".
// (use && or a ternary; 0 must add nothing)
// 4. console.log the line for each user.
//
// ✅ Expected output:
// 🟢 Ada (3)
// ⚫ Linus
const users = [
{ name: "Ada", isOnline: true, unread: 3 },
{ name: "Linus", isOnline: false, unread: 0 },
];
// your code here🎉 Lesson Complete
- ✅ Ternary cond ? a : b picks one of two
- ✅ && shows something only when true
- ✅ Avoid the 0-leak: test count > 0, not a bare count
- ✅ For many cases, use a variable or early returns, not nested ternaries
Practice quiz
When should you use a ternary instead of && for conditional rendering?
- When showing something or nothing
- When rendering a list
- When choosing between two different things to show
- Never; they are identical
Answer: When choosing between two different things to show. Use a ternary (cond ? a : b) to pick between two outputs; use && to show one thing or nothing.
What does {count && <Badge />} render when count is 0?
- A literal 0 on screen
- Nothing
- The Badge
- undefined
Answer: A literal 0 on screen. 0 is falsy, so && evaluates to 0 and React renders the literal 0. Use {count > 0 && <Badge />}.
Why can't you put an if statement directly inside JSX braces?
- if is too slow
- React disables if in JSX
- if only works in class components
- JSX braces hold expressions, and if is a statement
Answer: JSX braces hold expressions, and if is a statement. Braces contain expressions. Compute the value with if above the return, or use a ternary inside the braces.
What is the cleanest way to handle three or more rendering cases?
- Deeply nested ternaries
- Early returns or a lookup object
- Many && operators chained together
- A single if with no else
Answer: Early returns or a lookup object. For 3+ branches, prefer early returns (one element per case) or a lookup object over nested ternaries.
Which renders nothing when the condition is false?
- {cond && <X />}
- {cond ? <X /> : <Y />}
- {cond || <X />}
- {!cond}
Answer: {cond && <X />}. cond && <X /> shows <X /> only when cond is true; when false, React renders nothing.
You need to show a Spinner OR the Content. Which tool fits best?
- {loading && <Spinner/>}
- An if inside the braces
- A ternary: {loading ? <Spinner/> : <Content/>}
- A key prop
Answer: A ternary: {loading ? <Spinner/> : <Content/>}. Two mutually exclusive branches call for a ternary with an explicit else.
How do you safely avoid the '0 leaks onto the screen' trap?
- Use {count && ...}
- Test a real boolean, e.g. {count > 0 && ...}
- Wrap count in quotes
- Use a ternary with no else
Answer: Test a real boolean, e.g. {count > 0 && ...}. Convert to a boolean test like count > 0 (or Boolean(count)) so a zero never renders.
With early returns ordering cases, how should you order them?
- General case first, then specific
- Alphabetically
- Order does not matter
- Specific cases first, then the general/default last
Answer: Specific cases first, then the general/default last. Earlier returns win, so check specific states (loading, error) first and fall through to the default.
JSX is fundamentally what, which is why ordinary JS decides rendering?
- A template string
- An expression
- A statement
- A CSS rule
Answer: An expression. JSX is just an expression, so you use normal JavaScript (ternary, &&, variables) to choose what to show.
You want a fallback for the false branch, but && shows nothing. What should you switch to?
- Another &&
- An if inside JSX braces
- A ternary with an explicit else
- A for loop
Answer: A ternary with an explicit else. && renders nothing when false. For an explicit alternative, use a ternary: cond ? a : b.
Continue this course
- Previous: Handling Events
- Next: Lists & Keys — Render arrays with .map() and why every item needs a stable key
- Quick reference: React cheat sheet › Components & Props
Frequently asked questions
When should I use && vs a ternary?
Use && when you want to show something or nothing (one branch). Use a ternary condition ? a : b when you're choosing between two different things to show.
Why does a 0 sometimes show up on my screen?
Because {count && <Badge/>} returns the number 0 when count is 0, and React renders 0. Use a real boolean test: {count > 0 && <Badge/>}, or convert with {Boolean(count) && ...}.
Can I use if/else inside JSX?
Not directly inside the braces — JSX braces hold expressions, and if is a statement. Compute the value with an if/else (or early return) ABOVE the return, then drop the variable into the JSX.
How do I handle many cases cleanly?
For 3+ branches, prefer an early-return pattern (return one element per case) or a lookup object mapping a key to an element, rather than deeply nested ternaries.