CodeMIRAI
0 XP

Conditional rendering

2 min read 6 runnable examples Quiz included

if and an early return

React (JSX)
import { useState } from "react";

function Greeting({ user }) {
  if (!user) {
    return <p>Please sign in.</p>;
  }
  return <p>Welcome back, {user}!</p>;
}

function App() {
  const [user, setUser] = useState(null);
  return (
    <div>
      <Greeting user={user} />
      <button onClick={() => setUser(user ? null : "Asha")}>{user ? "Sign out" : "Sign in"}</button>
    </div>
  );
}

A component is a function, so ordinary if statements work. Returning early for the special case keeps the main markup unindented.

The ternary operator in JSX

React (JSX)
import { useState } from "react";

function App() {
  const [online, setOnline] = useState(true);
  return (
    <div>
      <p>{online ? "🟢 Online" : "⚪ Offline"}</p>
      <button onClick={() => setOnline(!online)}>Toggle</button>
    </div>
  );
}

if can't go inside JSX's braces, because only expressions can. condition ? a : b is an expression, so it can.

&& for "this or nothing"

React (JSX)
import { useState } from "react";

function App() {
  const [unread, setUnread] = useState(3);
  return (
    <div>
      <h3>
        Inbox{" "}
        {unread > 0 && (
          <span style={{ background: "#e0446a", color: "white", borderRadius: 999, padding: "2px 8px", fontSize: 13 }}>
            {unread}
          </span>
        )}
      </h3>
      <button onClick={() => setUnread(unread + 1)}>New message</button>{" "}
      <button onClick={() => setUnread(0)}>Mark all read</button>
    </div>
  );
}

condition && <Thing /> renders the thing when the condition is true, and nothing when it's false: React ignores false, null and undefined.

The 0 && trap

React (JSX)
function App() {
  const items = [];
  return (
    <div>
      <p>Wrong: {items.length && <span>{items.length} items</span>}</p>
      <p>Right: {items.length > 0 && <span>{items.length} items</span>}</p>
    </div>
  );
}

With an empty list, items.length && ... evaluates to 0, and React does render the number 0, so a stray "0" appears on the page. Make the left side a real true-or-false value, such as items.length > 0.

Several states: loading, error, success

React (JSX)
import { useState } from "react";

function Status({ state }) {
  switch (state) {
    case "loading":
      return <p>⏳ Saving...</p>;
    case "error":
      return <p style={{ color: "crimson" }}>Something went wrong. Try again.</p>;
    case "success":
      return <p style={{ color: "green" }}>✔ Saved!</p>;
    default:
      return null;
  }
}

function App() {
  const [state, setState] = useState("idle");
  return (
    <div>
      {["idle", "loading", "error", "success"].map((s) => (
        <button key={s} onClick={() => setState(s)} style={{ marginRight: 6 }}>{s}</button>
      ))}
      <Status state={state} />
    </div>
  );
}

A component that returns null renders nothing at all. When there are more than two cases, a switch in its own small component is easier to read than nested ternaries.

Conditional styles

React (JSX)
import { useState } from "react";

function Task({ label }) {
  const [done, setDone] = useState(false);
  return (
    <li
      onClick={() => setDone(!done)}
      style={{ cursor: "pointer", textDecoration: done ? "line-through" : "none", color: done ? "#999" : "inherit" }}
    >
      {done ? "✔ " : "○ "}{label}
    </li>
  );
}

function App() {
  return (
    <ul style={{ listStyle: "none", padding: 0 }}>
      <Task label="Read the lesson" />
      <Task label="Run the examples" />
      <Task label="Take the quiz" />
    </ul>
  );
}

Click a task to tick it off. The same ternary pattern works for className: className={done ? "task done" : "task"}.

Finished this lesson?Mark it complete to earn +20 XP and move your progress on.