Menu

React Conditional Rendering: if, Ternary, && and null

Conditional rendering in React is plain JavaScript: an if statement, a ternary or && decides which JSX a component returns. Learn each pattern, the stray 0 that && can print, returning null, and why hiding a component is not the same as not rendering it.

This page includes runnable editors - edit, run, and see output instantly.

Conditional rendering in React means choosing what a component returns with ordinary JavaScript: an if statement before the return, a ternary cond ? a : b inside the JSX, or cond && <Thing /> to show something or nothing. There is no special template syntax to learn.

Click the button and both the message and the label switch, because each ternary picks a different string on the next render. Change useState(false) to useState(true) and the preview starts logged in.

if statements and early returns

JSX braces accept expressions, not statements, so you cannot write {if (x) ...} inside the markup. You can write any if you like before the return. When a whole state of the component looks different (loading, error, empty), return early for each case and keep the main markup for the normal one.

Each button puts the inbox into a different state, and each state has its own short, readable branch. Early returns keep the happy path at the bottom without nesting.

Ternaries inside JSX

When only a small part of the markup changes, a ternary inline keeps it together: {isOpen ? <CloseIcon /> : <MenuIcon />}. Ternaries work well for two options. Nested ternaries for three or more get hard to read quickly:

// Hard to follow
{status === 'loading' ? <Spinner /> : status === 'error' ? <ErrorBox /> : <List />}

When you see that, move the logic into an if chain before the return (as above) or into an object map (further below).

&& and the stray 0

cond && <Thing /> renders <Thing /> when cond is truthy and nothing when it is false. It works because && returns its left side when that side is falsy, and React renders nothing for false, null and undefined.

The trap is that 0 is falsy too, and React does render numbers. So count && <Badge /> with a count of 0 puts a literal 0 on the page.

With no unread messages the first line reads "Broken: 0" while the second shows nothing after "Fixed:". Click New message and both agree; click Mark all read and the 0 comes back. The fix is to give && a real boolean: unread > 0, items.length > 0, or Boolean(unread). An empty string '' has the same problem in principle, but it renders as nothing visible, so you rarely notice it.

Returning null

A component can return null to render nothing. A warning banner that only appears when there is something to warn about is a good fit: the parent always renders <Warning /> and the component decides.

Watch the console: the Warning function logs on every render, including the ones where it returns null. Returning null skips the output, not the work. Its hooks and effects still run, so if a component is expensive or starts something (a timer, a subscription), decide in the parent and do not render it at all.

Storing JSX in a variable

JSX is a value, so you can assign it to a variable, build it up with if statements and drop it into the markup later. This helps when one piece of a larger layout depends on several conditions.

function Checkout({ cart, user }) {
    let action;
    if (!user) {
        action = <a href="/login">Log in to check out</a>;
    } else if (cart.length === 0) {
        action = <p>Your cart is empty.</p>;
    } else {
        action = <button>Pay now</button>;
    }

    return (
        <section>
            <h2>Your cart</h2>
            {action}
        </section>
    );
}

Choosing between several components with an object

When the choice is "one of many", an object that maps each value to a component is shorter than a long if chain or a switch, and adding a case is one line.

TABS[tab] picks a component, and <Panel /> renders it. The variable must start with a capital letter: JSX treats <panel /> as an HTML tag. Add a notifications entry to TABS with its own component and a fourth button appears.

Hiding is not the same as not rendering

There are two ways to make something disappear, and they behave differently. show && <Counter /> removes the component from the tree when show is false. React unmounts it and throws its state away, so it starts from scratch when it comes back. Hiding it with CSS (style={{ display: show ? 'block' : 'none' }}) keeps it mounted, so its state survives.

Click both counters a few times, uncheck the box, then check it again. The first counter is back at 0 and the second still holds its number. Neither is wrong: removing is right for a form that should start empty each time, hiding is right for tabs whose scroll position or input should be kept. The page on rendering explains how React decides that a component is the same one between renders.

React 19.2 adds a third option, <Activity mode="hidden">, which hides its children and keeps their state like CSS does, and also cleans up their effects until they are shown again.

Conditional props and attributes

Conditions are not only about which elements appear. Any prop can take a computed value, so a ternary or comparison inside an attribute is often all you need:

<button disabled={!canSave} className={hasError ? 'field error' : 'field'}>
    Save
</button>
<input aria-invalid={hasError} placeholder={user ? user.email : 'you@example.com'} />

When a prop's value is undefined, React leaves the attribute out entirely, which is a clean way to add an attribute only sometimes: title={isTruncated ? fullText : undefined}. For boolean attributes such as disabled and checked, pass true or false and React adds or removes them.

Conditions in lists

To leave items out of a list, filter the array before mapping it rather than returning null from inside map. items.filter((i) => i.done).map(...) reads as what it does, and the lists and keys page shows it in a running example.

Frequently Asked Questions

How do you write an if statement inside JSX?

You cannot put an if statement inside JSX braces, because braces take expressions. Use a ternary (cond ? a : b) or && inside the JSX, or run the if before the return and store the JSX in a variable.

Why does my component show a 0?

count && <Badge /> returns count itself when it is 0, and React renders the number 0. Make the left side a real boolean: count > 0 && <Badge />.

How do I render nothing in React?

Return null from the component, or put null, undefined, false or true in the JSX. React renders none of them.

Does a component that returns null still run?

Yes. Its function runs, its hooks run and its effects fire. Returning null only means it adds nothing to the page. To skip the work entirely, do not render the component from the parent.

Should I hide a component with CSS or remove it?

Removing it (show && <Panel />) unmounts it, so its state is thrown away and starts fresh next time. Hiding it with display: none keeps it mounted and keeps its state. Choose based on whether the state should survive.

Coddy programming languages illustration

Learn to code with Coddy

GET STARTED