What you'll learn
- Quick answer
- What conditional rendering means in React
- if statements and the early return
- The ternary operator for this-or-that
- Logical && to show or hide one thing
- The && with 0 gotcha (a stray 0 appears)
- Switching on state with three or more cases
- Loading, empty, and error states together
- Which pattern should you use?
- FAQ
Quick Answer
In React you render UI conditionally in a few ways: an if statement (usually as an early return) to pick between whole blocks, a ternary (cond ? a : b) for this-or-that inside JSX, and logical && to show something or nothing. Reach for early returns when a component has several states like loading, error, and empty. Just watch the && with 0 gotcha: 0 && something renders a stray 0, so test with cart.length > 0 instead of cart.length.
What conditional rendering means in React
React conditional rendering just means showing different UI depending on your data or state. Logged in? Show the dashboard. Still loading? Show a spinner. Cart empty? Show a friendly message instead of an empty box.
Here is the key idea that trips up beginners: JSX is not HTML. Everything inside curly braces { } is a JavaScript expression — something that produces a value. That is why you cannot drop a full if statement inside JSX, but you can use a ternary or &&, because those are expressions.
React also treats some values as "render nothing": false, null, undefined, and true all produce no output. That single rule is what makes patterns like && work — and it is also behind the most common bug, which we will get to. Let's walk through each pattern with code you can actually run.
if statements and the early return
The most readable pattern for whole-block choices is a plain if placed before the return. When a condition means "don't render the normal thing at all," return early:
function Greeting({ user }) {
if (!user) {
return <p>Please log in to continue.</p>;
}
return <h1>Welcome back, {user.name}!</h1>;
}This is called a guard clause. Because we return inside the if, the rest of the function only runs when user exists — so below that line you can safely use user.name without extra checks.
You can also use if to build up the JSX in a variable, then render it once:
function Price({ isMember, amount }) {
let label;
if (isMember) {
label = <span>Member price: ₹{amount}</span>;
} else {
label = <span>Price: ₹{amount}</span>;
}
return <div>{label}</div>;
}Both are fine. Early returns are usually cleaner when a component has several distinct states.
The ternary operator for this-or-that
When you need to choose between two things inside JSX, the ternary operator condition ? a : b is the tool. It is an expression, so it fits right between curly braces:
function Status({ isOnline }) {
return (
<p>
Status: {isOnline ? "Online" : "Offline"}
</p>
);
}It works for whole elements too, not just text:
function AuthButton({ user }) {
return (
<div>
{user
? <button>Log out</button>
: <button>Log in</button>}
</div>
);
}The ternary shines when you truly have two outcomes. If one side is "show nothing," you can write {cond ? <Thing /> : null} — and that is actually a safe habit. But for the plain "show something or nothing" case, most people reach for && instead, which we'll cover next.
One warning: avoid nesting ternaries (a ? b : c ? d : e). It technically works but becomes unreadable fast. If you have three or more cases, use early returns or an object map instead.
Logical && to show or hide one thing
Very often you want to render something only when a condition is true, and render nothing otherwise. That is exactly what && does:
function Inbox({ unread }) {
return (
<div>
<h2>Inbox</h2>
{unread > 0 && <span className="badge">{unread} new</span>}
</div>
);
}How it works: JavaScript's && "short-circuits." If the left side is falsy, it returns the left value; if the left side is truthy, it returns the right value. So when unread > 0 is true, the expression becomes the <span>. When it is false, the expression becomes false — and React renders nothing for false. Clean.
This is the go-to pattern for optional badges, alerts, tooltips, and "show more" sections. It reads almost like English: "unread is positive AND show this badge." But there is a sharp edge hiding in that word falsy.
The && with 0 gotcha (a stray 0 appears)
Here is the bug almost every React beginner hits at least once:
// BUG: renders a literal 0 when the cart is empty
function Cart({ items }) {
return (
<div>
{items.length && <p>You have {items.length} items</p>}
</div>
);
}When items is empty, items.length is 0. In JavaScript 0 is falsy, so 0 && <p>...</p> short-circuits and the whole expression becomes 0. And unlike false or null, React does render the number 0. So instead of nothing, you see a lonely 0 on the page.
The fix is to hand && a real boolean on the left, not a number:
// FIX 1: compare to make it a real boolean
{items.length > 0 && <p>You have {items.length} items</p>}
// FIX 2: coerce to boolean
{Boolean(items.length) && <p>...</p>}
// FIX 3: use a ternary with null
{items.length ? <p>You have {items.length} items</p> : null}Rule of thumb: the left side of && should be a boolean, never a number or a string. If it might be 0 or "", convert it first with a comparison like > 0. This one habit prevents the most common conditional-rendering bug in React.
Switching on state with three or more cases
Ternaries and && are for two outcomes. When a component can be in three or more named states — say a status stored in state — reach for a switch or an object lookup instead of nesting ternaries.
A switch inside a small helper reads clearly:
function OrderBadge({ status }) {
switch (status) {
case "paid":
return <span>✅ Paid</span>;
case "pending":
return <span>⏳ Pending</span>;
case "failed":
return <span>❌ Failed</span>;
default:
return <span>Unknown</span>;
}
}An object map is even shorter when each case is a simple value:
function OrderBadge({ status }) {
const labels = {
paid: "✅ Paid",
pending: "⏳ Pending",
failed: "❌ Failed",
};
return <span>{labels[status] ?? "Unknown"}</span>;
}The ?? "Unknown" is a safe fallback for any status not in the map. Object maps are great for turning a state string into a label, an icon, or a CSS class.
Loading, empty, and error states together
Real screens that fetch data usually have four states: loading, error, empty, and success. The cleanest way to handle all of them is a stack of early returns — one guard per state, in order:
function UserList({ status, users, error }) {
if (status === "loading") {
return <p>Loading…</p>;
}
if (status === "error") {
return <p>Something went wrong: {error}</p>;
}
if (users.length === 0) {
return <p>No users yet.</p>;
}
// success: we only reach here with real data
return (
<ul>
{users.map((u) => (
<li key={u.id}>{u.name}</li>
))}
</ul>
);
}Read it top to bottom like a checklist. Each guard removes one possibility, so by the final return you know the data is loaded, valid, and non-empty. No nested ternaries, no stray 0, and every case has its own clear branch. Notice the empty check uses users.length === 0 — an explicit comparison, exactly the habit that avoids the && gotcha.
Don't forget the key prop on each item in the mapped list — React needs a stable, unique key to update lists efficiently.
Which pattern should you use?
There is no single "best" pattern — each fits a different shape of problem. Here is a quick guide:
| Pattern | Best for | Works inside JSX | Handles 3+ cases |
| if / early return | Guard clauses, loading/error/empty | No | Yes |
| Ternary ? : | This-or-that, two outcomes | Yes | Only if not nested |
| Logical && | Show one thing or nothing | Yes | No |
| switch / object map | Many named states | In a helper | Yes |
My recommendation for beginners: use && for optional bits of UI, a ternary when you have exactly two outcomes, and early returns once a component juggles several states. Keep conditions simple — if a line gets hard to read, pull the logic out into a variable or a small helper component above your return.
Conditional rendering is one of those React skills that clicks with practice. If you want a guided path from JSX and state all the way to full apps, our free React course walks through each of these patterns with hands-on projects.
Frequently Asked Questions
Why is a random 0 showing up in my React component?
You almost certainly wrote something like {items.length && <Thing />}. When the array is empty, items.length is 0, which is falsy, so && returns 0 — and React renders the number 0. Fix it by giving && a real boolean: use {items.length > 0 && <Thing />} instead.
Can I use an if/else statement directly inside JSX?
No. Only JavaScript expressions are allowed inside JSX curly braces, and if is a statement, not an expression. Put the if above your return (often as an early return), or use an expression like a ternary or && inside the JSX itself.
Ternary or &&, which one should I use?
Use a ternary (cond ? a : b) when you genuinely have two outcomes to show. Use && when you want to show one thing or nothing at all. If you find yourself writing cond ? <X /> : null, that is a fine, safe alternative to && that also avoids the stray-0 bug.
How do I render different UI for more than two conditions?
Avoid nesting ternaries — they get unreadable quickly. For three or more cases, use a stack of early returns (great for loading/error/empty/success), a switch statement inside a helper, or an object map that turns a state string into the value you want to show.
Which values render nothing in React?
React renders nothing for false, null, undefined, and true. It does render the number 0 and empty strings, which is exactly why the && with 0 bug happens. When in doubt, return null to render nothing on purpose.
Is conditional rendering bad for performance?
No, these patterns are cheap and idiomatic React — evaluating a ternary or && costs almost nothing. Just remember that when a condition flips, React mounts or unmounts that part of the tree, so any component being shown will run its effects and lose its local state each time it reappears.
