Topics in this subject
React 4 min read Updated 6 Aug 2026

Conditional Rendering

Rendering UI conditionally with &&, ternary, early return null, JSX variables, and the 0-renders bug.

🧑‍🏫 Sabse pehle — simple mein samjho#

UI mein bhi if-else chalta hai: jab kuch sach ho tabhi dikhao. Do common tareeke — {condition && <X/>} (condition sach to X dikhao) aur cond ? <A/> : <B/> (sach to A, warna B). Jaise ghar pe "agar mehmaan aaye to hi chai banao" — condition poori to hi kaam. Ek gotcha: {count && <X/>} mein jab count 0 ho to screen pe 0 chhap jata hai, isliye count > 0 && ... likho.

function Cart({ count }) {
  return (
    <div>
      {count > 0 && <p>{count} items</p>}   {/* sach to hi dikhega */}
      {count > 0 ? <button>Checkout</button> : <p>Cart khaali hai</p>}
    </div>
  );
}

Yaad rakho: && se dikhao/chhupao, ? : se do mein se ek choose karo — aur 0 wale gotcha se bacho.

The core idea#

JSX is just expressions, so conditional rendering is ordinary JS producing React nodes. React renders null, undefined, false, and true as nothing — but not 0 or "" (those are printed). 🎯

function Notifications({ items }) {
  if (!items) return null;            // early return: render nothing
  const empty = items.length === 0;

  return (
    <div>
      {empty ? <Empty /> : <List items={items} />}  {/* ternary: either/or */}
      {items.length > 0 && <Badge n={items.length} />}  {/* && : maybe */}
    </div>
  );
}

Techniques compared#

Technique Use when Note
cond && <X/> Show X or nothing ⚠️ guard the left side (see below)
cond ? <A/> : <B/> One of two branches Nesting ternaries hurts readability
if (...) return null Whole component renders nothing 🟢 cleanest for guard clauses
JSX in a variable Complex multi-branch logic Compute above return, keep JSX flat
// 🟢 Variable holding JSX keeps the returned tree readable
let content;
if (status === "loading") content = <Spinner />;
else if (status === "error") content = <Error />;
else content = <Data value={data} />;

return <section>{content}</section>;

Real-world example: a Flipkart/Myntra-style navbar 🎯#

A header that swaps Login for a Profile menu, plus a cart badge, exercises all three techniques at once:

function ProfileMenu({ user }) {
  if (!user) return null; // early return: nothing to render pre-login
  return (
    <div className="profile-menu">
      <Avatar user={user} />
      <button onClick={logout}>Logout</button>
    </div>
  );
}

function Navbar({ user, cartCount }) {
  return (
    <nav>
      <Logo />

      {/* ternary: exactly one of two branches, never both */}
      {user ? <ProfileMenu user={user} /> : <button onClick={openLogin}>Login</button>}

      {/* && : show the badge, or nothing — but watch what "nothing" means for 0 */}
      {cartCount && <span className="badge">{cartCount}</span>}
    </nav>
  );
}

When the cart is empty, cartCount is 0 — a real, valid number, but falsy. {cartCount && <span>...} then renders the literal digit 0 as a stray badge next to the cart icon, a bug that's easy to ship on exactly this kind of header:

// ⚠️ empty cart still shows a naked "0" pill on the navbar
{cartCount && <span className="badge">{cartCount}</span>}

// 🟢 coerce to a real boolean first
{cartCount > 0 && <span className="badge">{cartCount}</span>}
flowchart TD
  A["Navbar renders"] --> B{"user present?"}
  B -->|"yes"| C["Ternary true branch: ProfileMenu (Avatar + Logout)"]
  B -->|"no"| D["Ternary false branch: Login button"]
  C --> E{"cartCount value"}
  D --> E
  E -->|"0 (falsy, but a real number)"| F["cartCount && <Badge/> prints literal '0' ⚠️"]
  E -->|"greater than 0"| G["cartCount && <Badge/> renders the badge 🟢"]
  E -->|"guarded as cartCount > 0"| H["Real boolean: badge or nothing, never a stray 0 🟢"]

⚠️ The count && <X/> bug#

&& returns its left operand when that operand is falsy. If the left side is the number 0, React renders the 0 on screen instead of nothing.

{count && <Cart />}        // ⚠️ when count === 0 → renders literal "0"
{count > 0 && <Cart />}    // 🟢 coerce to a real boolean
{count ? <Cart /> : null}  // 🟢 ternary is unambiguous
{!!items.length && <List/>}// 🟢 double-bang forces boolean

Same trap with empty strings inside && chains — always ensure the left operand is a genuine boolean.

flowchart TD
  A["Expression in JSX"] --> B{"Value type?"}
  B -->|"null / undefined / true / false"| C["Renders nothing"]
  B -->|"0 or empty string"| D["Renders the value ⚠️"]
  B -->|"React element"| E["Renders the element"]

Interview Q&A#

Q1. Why does {count && <X/>} render 0 when count is zero? && short-circuits and returns the left operand when it is falsy. 0 is falsy but is a valid React child, so React prints 0. Use count > 0 && or a ternary.

Q2. Which falsy values does React skip rendering? null, undefined, true, and false render as nothing. 0 and "" are rendered as text.

Q3. Ternary vs && — when do you pick each? Use && for "show this or nothing", and a ternary for "show A or B". A ternary is also the safe choice when the condition might be a number.

Q4. Is early return null different from returning false? Both render nothing. return null is the idiomatic, explicit signal that a component intentionally renders no output; returning false works but reads as accidental.