Conditional Rendering
Learn how to show, hide, or swap pieces of UI in React based on state — using &&, the ternary operator, and early returns.
Most apps don't look the same every second. A login page disappears once you sign in. An error message appears only when something goes wrong. A loading spinner shows while data is fetching, then vanishes the moment it arrives.
This is conditional rendering — the ability to show or hide parts of your UI based on some condition. In React it isn't a special feature you have to learn separately; it's just JavaScript, used right inside your JSX. Once it clicks, you'll wonder how you ever built UIs without it.
A Velvet Rope at a Club
Think of conditional rendering like a bouncer with a velvet rope. The bouncer checks a condition — "Are you on the list?" If yes, you get in (the element renders). If no, you stay outside (nothing renders). The rope itself is invisible to the people who sail through. Your UI works exactly the same way — only the elements that pass the condition make it onto the screen.
#Pattern 1: && for Show or Hide
function Inbox({ unreadCount }) {
return (
<div>
<h2>Inbox</h2>
{unreadCount > 0 && (
<p className="badge">{unreadCount} unread messages</p>
)}
</div>
);
}Watch Out for 0
0 is falsy — but React will render the digit 0 on screen instead of nothing. This catches everyone at least once.
```jsx // BUG: renders "0" when items.length is 0 {items.length && <List items={items} />}
// SAFE: compare explicitly {items.length > 0 && <List items={items} />} ```
Whenever the left side of && might be a number, add a > 0 comparison to convert it to a proper boolean.
#Pattern 2: Ternary for Either/Or
function UserCard({ isLoggedIn, username }) {
return (
<div>
{isLoggedIn ? (
<p>Welcome back, {username}!</p>
) : (
<p>Please sign in to continue.</p>
)}
<button>{isLoggedIn ? 'Log out' : 'Log in'}</button>
</div>
);
}#Pattern 3: Early Return
function Profile({ user, isLoading }) {
if (isLoading) return <p>Loading...</p>;
if (!user) return <p>No user found.</p>;
return (
<div>
<h2>{user.name}</h2>
<p>{user.bio}</p>
</div>
);
}#Putting It Together: Rendering Based on State
Conditional rendering becomes really powerful when the condition is a piece of state. Changing state triggers a re-render, and the component recalculates which JSX to return — so the UI updates automatically, with no manual DOM work.
import { useState } from 'react';
function Spoiler({ text }) {
const [revealed, setRevealed] = useState(false);
return (
<div>
{revealed ? (
<p>{text}</p>
) : (
<p style={{ filter: 'blur(6px)' }}>Hidden</p>
)}
<button onClick={() => setRevealed(prev => !prev)}>
{revealed ? 'Hide' : 'Reveal'}
</button>
</div>
);
}Extract Complex Conditions
If your condition involves several checks, pull it into a named variable above the return — it keeps your JSX readable and makes the logic easy to scan.
``jsx const showWelcome = isLoggedIn && user !== null && !user.isBanned; return <div>{showWelcome && <WelcomeBanner />}</div>; ``
You want to render a <Sale /> component only when a boolean `isSaleActive` is true, and render nothing otherwise. Which pattern is most appropriate?
Key takeaways
- Use `condition && <Element />` to show something or render nothing — always use `> 0` comparisons when the condition might be a number, to avoid accidentally rendering `0`.
- Use `condition ? <A /> : <B />` to swap between two different elements, labels, or whole sections of markup.
- Use an early `return null` (or a fallback) at the top of a component to bail out before the main UI when data is missing, loading, or in an error state.
- Pairing conditional rendering with state means your UI updates automatically whenever the underlying data changes — no manual DOM work needed.
- When conditions grow complex, extract them into clearly-named variables above your `return` statement to keep JSX readable.
This code has a bug — what's wrong?
function Cart({ items }) {
return (
<div>
<h2>Cart</h2>
{items.length && <p>You have items!</p>}
</div>
);
}Complete this show-or-nothing pattern: render the badge ONLY when unreadCount is greater than zero, and render nothing otherwise. Fill in the operator that renders its right side only when the left side is truthy.
function Inbox({ unreadCount }) { return ( <div> <h2>Inbox</h2> {unreadCount > 0 <p>{unreadCount} unread</p>} </div> ); }
Arrange these lines into a correct Profile component that uses early-return guard clauses: show a loading message while fetching, a fallback if there is no user, then the profile card otherwise.
);
if (isLoading) return <p>Loading...</p>;
}
<div><h2>{user.name}</h2></div>function Profile({ user, isLoading }) {return (
if (!user) return <p>No user found.</p>;
The Spoiler component starts with revealed = false. What is on screen BEFORE the user clicks anything?
function Spoiler({ text }) {
const [revealed, setRevealed] = useState(false);
return (
<div>
{revealed ? <p>{text}</p> : <p>Hidden</p>}
<button onClick={() => setRevealed(prev => !prev)}>
{revealed ? 'Hide' : 'Reveal'}
</button>
</div>
);
}Build a PasswordInput component. It should render a text input and a toggle button. When the button is clicked, it switches the input between type="password" (text hidden) and type="text" (text visible). The button label should say "Show" when the password is hidden and "Hide" when it is visible.
Try it live — edit the code and hit Run to see it rendered: