Frontend Master

JavaScript Curriculum

Conditional Rendering
+50 XP

Conditional Rendering

easy
~25 min·50 XP

The coffee shop menu needs to show a loading skeleton while data fetches, an error message if it fails, an empty state if there are no items, and the actual menu when data is ready. Four states, four different UIs — all from one component.

Conditional Rendering

React components return different JSX based on state and props. There is no special directive — just JavaScript expressions inside JSX.

Five Conditional Patterns

Know which pattern to reach for in each situation:

conditional-patterns.jsx

The most common pattern. Shows A or B based on a condition. Works anywhere in JSX.

Use when: Show one of two things — render A or render B.
function StatusBadge({ isOnline }) {
  return (
    <span className={isOnline ? 'badge-green' : 'badge-grey'}>
      {isOnline ? 'Open' : 'Closed'}
    </span>
  )
}

// Works for classes too:
<div className={`card ${featured ? 'featured' : ''}`}>
🟢 Open
⚠️The 0 trap with &&
`{count && <Badge />}` renders "0" when count is 0 because 0 is falsy but React renders it as text. Always use a boolean: `{count > 0 && <Badge />}`. This is the most common conditional rendering bug in React.

Loading / Error / Empty / Data — The Four States

Every component that fetches data needs to handle all four render states:

render-states.jsx
Component output
Espresso£2.50
Cappuccino£3.50
Early return pattern
function MenuList({ isLoading, error, items }) {
  if (isLoading) return <Spinner />
  if (error)     return <ErrorMessage error={error} />
  if (!items.length) return <EmptyState />

  return (
    <ul>
      {items.map(item => <MenuItem key={item.id} {...item} />)}
    </ul>
  )
}
Handle special cases first with early returns. The main render only runs when everything is ready — no nested ternaries needed.
💡Early returns keep code flat
Instead of deeply nested ternaries, use early returns for each special state. The main render at the bottom only runs when data is ready. Each guard clause is a single line — easy to read, easy to add new states.

Loading State Patterns — Skeletons vs Spinners

See loading, success, and error states in a live demo:

loading-states.jsx
Click a button to simulate a fetch
function Menu() {
  const [status, setStatus] = useState('idle')
  const [data, setData]     = useState(null)

  if (status === 'loading') return <Skeleton />
  if (status === 'error')   return <ErrorCard onRetry={fetch} />
  if (!data)                return null

  return data.map(item => <MenuCard key={item.id} {...item} />)
}
ℹ️Skeleton UIs beat spinners
Skeleton loaders (grey placeholder shapes) feel faster than spinners because they show the layout before the content arrives. The user brain fills in the gaps. Use skeletons for list items and cards — spinners for full-page or button loading.

Your Challenge

Build MenuList({ isLoading, error, items }). Use early returns: if (isLoading) return <Skeleton />, if (error) return <ErrorCard />, if (!items.length) return <EmptyState />. Main render: map items to cards. Wire it to a parent that toggles these states with buttons.

Challenge

Build a MenuList component that handles four render states: loading (skeleton), error (message + retry), empty (friendly message), data (list of items). Use early returns for the first three. Never render loading and error at the same time.

conditional-renderingternarylogical-andearly-returnnullish-coalescingloading-stateerror-stateempty-statezero-trapskeleton-ui
Conditional Rendering | Nexus Learn