Chapter 08 of 14 · browse all
Chapter 08

Conditional Rendering

Showing different output for different data, using ordinary JavaScript rather than special syntax.

An early return

The clearest option when whole branches differ is a plain if before the JSX.

function Status({ user }) {
  if (!user) {
    return <p>Please sign in.</p>;
  }

  return <p>Signed in as {user.name}</p>;
}

The ternary operator

Inside JSX you need an expression, so a conditional becomes a ternary.

function Status({ isOnline }) {
  return (
    <p className={isOnline ? "online" : "offline"}>
      {isOnline ? "Online" : "Offline"}
    </p>
  );
}

Ternaries nest, but two levels is usually the point at which a variable or a separate component reads better.

Logical AND for show-or-nothing

function Inbox({ unread }) {
  return (
    <div>
      <h2>Inbox</h2>
      {unread > 0 && <span className="badge">{unread} new</span>}
    </div>
  );
}

There is a trap here. If the left side is the number 0, React renders the zero instead of nothing, because 0 && x evaluates to 0 and React renders numbers.

// Renders a stray "0" when items is empty
{items.length && <List items={items} />}

// Renders nothing when items is empty
{items.length > 0 && <List items={items} />}

false, null, undefined, and true all render as nothing. Numbers and strings render as themselves — which is why 0 leaks through.

Assigning to a variable

When several conditions combine, building the element in a variable keeps the returned JSX readable.

function Message({ status }) {
  let content;

  if (status === "loading") {
    content = <Spinner />;
  } else if (status === "error") {
    content = <p className="error">Could not load. Try again.</p>;
  } else {
    content = <Report />;
  }

  return <div className="panel">{content}</div>;
}

Switching on a value

For a fixed set of cases, an object map is compact and avoids a chain of comparisons.

const icons = {
  success: <CheckIcon />,
  warning: <AlertIcon />,
  error: <CrossIcon />,
};

function Notice({ kind, children }) {
  return (
    <div className={`notice notice-${kind}`}>
      {icons[kind] ?? null}
      {children}
    </div>
  );
}

Conditional attributes

The same expressions work inside attributes.

<button
  className={isActive ? "tab tab-active" : "tab"}
  disabled={isSaving}
  aria-current={isActive ? "page" : undefined}
>
  Overview
</button>

Passing undefined removes an attribute entirely, which is often what you want for ARIA attributes.