ReactConditional Rendering

Conditional Rendering

One of the most powerful aspects of React is that your UI is just JavaScript. That means you can use all of JavaScript's control flow — if, else, ternaries, logical operators — to decide what to render. React doesn't have a special template directive like v-if or *ngIf; you use plain JavaScript expressions instead.

if/else Before the Return

The simplest and most readable approach is an if statement above the return. Extract complex conditions here to keep your JSX clean:

JSX
function UserGreeting({ user, isLoading }) {
  if (isLoading) {
    return <p>Loading...</p>
  }

  if (!user) {
    return <p>Please log in.</p>
  }

  return <h1>Welcome back, {user.name}!</h1>
}

This is excellent for early returns — guard clauses that bail out before the main render logic. Each condition is easy to read and debug.

Ternary Operator in JSX

Inside JSX you can't use if statements (they're not expressions). The ternary operator condition ? ifTrue : ifFalse works because it's an expression that produces a value:

JSX
function SubscribeButton({ isSubscribed, onToggle }) {
  return (
    <button onClick={onToggle}>
      {isSubscribed ? 'Unsubscribe' : 'Subscribe'}
    </button>
  )
}

// Ternary can also switch entire elements
function StatusBadge({ status }) {
  return (
    <span className="badge">
      {status === 'online'
        ? <span className="green">● Online</span>
        : <span className="red">● Offline</span>
      }
    </span>
  )
}
The && Operator (Single-Branch Rendering)

When you only want to render something if a condition is true — and render nothing if it's false — use the && operator:

JSX
function Notification({ message, count }) {
  return (
    <div>
      <h2>Inbox</h2>
      {count > 0 && <p>You have {count} unread messages.</p>}
      {message && <div className="alert">{message}</div>}
    </div>
  )
}

// When count=0: <p> is not rendered
// When count=3: renders "You have 3 unread messages."
Warning
**The 0 gotcha**: `&&` renders its left side if it's falsy — but `0` is falsy AND renders as the character "0" in the DOM. Write `count > 0 && ...` or `Boolean(count) && ...` instead of `count && ...` to avoid accidentally rendering "0" on screen. ```jsx // ✗ Bug: renders "0" when count is 0 {count && <p>{count} messages</p>} // ✓ Correct: renders nothing when count is 0 {count > 0 && <p>{count} messages</p>} ```
Nullish Coalescing (??) for Fallbacks

?? returns its right side only when the left side is null or undefined (not other falsy values like 0 or ""):

JSX
function UserProfile({ user }) {
  return (
    <div>
      <h2>{user.displayName ?? user.email}</h2>
      <p>{user.bio ?? 'No bio provided.'}</p>
      <p>Posts: {user.postCount ?? 0}</p>
    </div>
  )
}

// user.postCount = 0  → shows "Posts: 0" (correct, 0 is valid)
// user.postCount = null → shows "Posts: 0" (correct, falls back)
// Whereas user.postCount || 0 would show "Posts: 0" for postCount=0 too
// but would incorrectly show 0 for postCount="" (empty string)
switch for Multiple Conditions

When you have more than two branches, a switch statement above the return is cleaner than nested ternaries:

JSX
function RequestStatus({ status }) {
  switch (status) {
    case 'idle':
      return null
    case 'loading':
      return <Spinner />
    case 'success':
      return <SuccessMessage />
    case 'error':
      return <ErrorMessage />
    default:
      return <p>Unknown status: {status}</p>
  }
}

// Or with an object lookup for compact inline logic
const STATUS_ICON = {
  loading: '⏳',
  success: '✓',
  error: '✗',
  idle: '–',
}

function StatusIcon({ status }) {
  return <span>{STATUS_ICON[status] ?? '?'}</span>
}
Rendering null (Render Nothing)

Returning null from a component (or including null in JSX) renders nothing — no DOM node, no empty element. This is React's explicit "render nothing" value.

JSX
// A component that renders nothing when not visible
function Toast({ message, visible }) {
  if (!visible) return null // component renders nothing

  return (
    <div className="toast">
      {message}
    </div>
  )
}

// null in JSX expressions also renders nothing
function Panel({ showFooter, children }) {
  return (
    <div>
      {children}
      {showFooter ? <footer>Footer content</footer> : null}
    </div>
  )
}
Note
Returning `null` is different from returning `undefined` — React accepts `null` as a valid "render nothing" value. Returning `undefined` from a component body is an error. Always return `null` when you want a component to render nothing.
Extracting Conditional JSX to Variables

When conditional logic gets complex, extract it to a variable before the return statement to keep your JSX readable:

JSX
function ProductCard({ product, user }) {
  // Compute what to show before the return
  let priceDisplay
  if (!user) {
    priceDisplay = <span>Log in to see price</span>
  } else if (user.isPremium) {
    priceDisplay = <span className="premium">${product.premiumPrice}</span>
  } else {
    priceDisplay = <span>${product.regularPrice}</span>
  }

  return (
    <div className="product-card">
      <img src={product.image} alt={product.name} />
      <h3>{product.name}</h3>
      {priceDisplay}
    </div>
  )
}
Choosing the Right Pattern
  • Early return / if-else before return — best for component-level guards, loading states, error states

  • Ternary ? : — best for two-branch inline JSX choices

  • && operator — best for single-branch show/hide (but watch the 0 gotcha)

  • ?? operator — best for null/undefined fallback values

  • switch statement — best for 3+ named conditions

  • Variable extraction — best when the conditional logic is complex or reused

Tip
Deeply nested ternaries are hard to read and debug. The rule of thumb: if you'd need to mentally trace through more than two levels of nesting to understand what renders, extract the logic to variables or helper functions.