Section 2 · Components & Props
Conditional Rendering
14 min3 min readCode playground
Lesson at a glance
Show, hide and switch UI based on data using early returns, the ternary operator and &&, while avoiding the stray “0” bug and unreadable nested conditions.
- 1Early return: whole alternatives
- 2Ternary: one thing or another
- 3&&: something or nothing
- 4Conditions in attributes
- 5Picking the right tool
- 6Not rendering versus hiding
No video here — just the real thing: a written lesson, runnable examples, a quiz and practice.
Real interfaces change shape with the data. The Watchlist shows a “Watched” badge on some movies but not others, an encouraging message when the list is empty, and a disabled Add button until you type a title. None of that needs special React syntax. It’s plain JavaScript deciding which JSX to return, and there are three tools for it.
Early return: whole alternatives
When a component shows something entirely different in one case, handle that case first and return:
export default function MovieList({ movies }) {
if (movies.length === 0) {
return <p className="empty">Nothing to watch yet. Add a movie above.</p>;
}
return (
<ul>
{movies.map((movie) => (
<li key={movie.id}>{movie.title}</li>
))}
</ul>
);
}The empty case is dealt with in two lines, and the rest of the function only worries about the normal case. This is the most readable pattern, so reach for it first. (The map and key are the topic of the next lesson.)
A component can also return null to render nothing at all:
function WatchedBadge({ watched }) {
if (!watched) return null;
return <span className="badge">Watched</span>;
}Ternary: one thing or another
Inside JSX, where you can’t write if, use the conditional operator for a choice between two outputs:
<p className="status">
{movie.watched ? 'Watched' : 'To watch'}
</p>It works for elements too: {isEditing ? <TitleInput /> : <h2>{title}</h2>}. Keep ternaries short. Once you nest one ternary inside another, or the branches run to several lines each, move the decision into a variable above the return, or into its own small component.
&&: something or nothing
When the alternative is “nothing”, the logical AND operator is shorter than a ternary with null:
<li>
{movie.title}
{movie.watched && <span className="badge">Watched</span>}
</li>JavaScript evaluates a && b to a if a is falsy, otherwise to b. When movie.watched is false, the expression is false, and React renders nothing for false. When it’s true, you get the badge.
Conditions in attributes
Conditions aren’t only about whole elements. Attributes take expressions too:
<li className={movie.watched ? 'movie movie-watched' : 'movie'}>
{movie.title}
</li>
<button disabled={title.trim() === ''}>Add</button>
<button aria-pressed={filter === 'watched'}>Watched</button>The third one matters for accessibility: aria-pressed tells screen reader users which toggle button is active, which a color change alone doesn’t. When a value is false or null for a boolean attribute like disabled, React leaves it off the element.
Picking the right tool
All three patterns produce the same kind of result, so the choice is about readability. A rule of thumb that holds up well in code review:
- The whole output changes (loading, error, empty, normal): early return, one case at a time, top to bottom.
- One spot switches between two things: a ternary, kept to a line or two per branch.
- One spot is either there or not:
&&with a real boolean on the left.
When you notice yourself writing a ternary inside a ternary, or an && chain with three conditions, stop and give the logic a name. Either compute a variable (const status = …) above the return, or extract a small component such as WatchedBadge that hides the decision inside itself. The parent then reads like a sentence: title, badge, actions.
Order matters with early returns, too. Put the cases that make the rest impossible first. If a movie list can be loading, failed or empty, check them in that order, so the final return only ever deals with real data.
Not rendering versus hiding
There’s an important difference between these two:
{showWatched && <WatchedPanel />}
<div hidden={!showWatched}>
<WatchedPanel />
</div>The first removes WatchedPanel from the tree when the condition is false. React unmounts it: its DOM goes away and any state inside it, such as text typed into an input, is destroyed. When it comes back, it starts fresh. The second keeps it mounted and only hides its wrapper (the HTML hidden attribute works like display: none), so the state survives.
Most of the time you want the first; there’s no reason to keep invisible UI alive. Choose hiding when the user expects their in-progress work inside the hidden part to still be there, as in tabs with half-filled forms.
Next, you’ll render the whole movie list from data with map, and learn why React keeps asking you for a key.
Key takeaways
- Use an early
returnfor whole alternative screens, a ternary for one of two things, and&&for something or nothing. - A component can return
nullto render nothing at all. {count && <List />}renders a literal 0 when count is 0; compare explicitly withcount > 0 &&.- Conditions can drive attributes too, such as
className,disabledandaria-pressed. - Not rendering a component removes it and its state; hiding it with CSS keeps both.