Skip to content

React Tutorial JSX and Components

Conditional Rendering in React

Lesson 29 of 156 2 min read By Deepak Paswan Updated Oct 10, 2026

Runnable lesson · press Try it on the examples to edit and run them here.

Real interfaces change with data: a logged-in user sees a different menu, an empty cart shows a message, an error shows a warning. In React you do this with plain JavaScript conditions.

1. An if statement before return

Best when the whole component should look different:

App.jsx
JSX
function Greeting({ loggedIn }) {
  if (loggedIn) {
    return <p>Welcome back!</p>;
  }
  return <p>Please log in.</p>;
}

function App() {
  const [loggedIn, setLoggedIn] = React.useState(false);
  return (
    <div>
      <Greeting loggedIn={loggedIn} />
      <button onClick={() => setLoggedIn(true)}>Log in</button>
    </div>
  );
}

A component can return null to render nothing.

2. The ternary operator

Best for choosing between two pieces of JSX:

App.jsx
JSX
function App() {
  const [on, setOn] = React.useState(false);
  return (
    <div>
      <p>Switch is {on ? "On" : "Off"}</p>
      <button onClick={() => setOn(!on)}>Toggle</button>
    </div>
  );
}

3. Logical AND (&&): show or nothing

Best when there is no “else” branch:

App.jsx
JSX
function App() {
  const [items, setItems] = React.useState(2);
  return (
    <div>
      <p>Items in cart: {items}</p>
      {items > 0 && <button>Checkout</button>}
      <button onClick={() => setItems(0)}>Empty cart</button>
    </div>
  );
}

Always make the left side a real boolean (items > 0, not just items), or React will print a stray 0 when the number is zero. See Rendering Dynamic Values.

4. Choose among many with an object or switch

Nested ternaries get hard to read. For three or more cases, use a lookup object or a switch in a helper:

App.jsx
JSX
const views = {
  loading: <p>Loading...</p>,
  success: <p>Data loaded</p>,
  error: <p>Something went wrong</p>,
};

function App() {
  const order = ["loading", "success", "error"];
  const [index, setIndex] = React.useState(0);
  const status = order[index];
  return (
    <div>
      {views[status]}
      <button onClick={() => setIndex((index + 1) % order.length)}>Next</button>
    </div>
  );
}

5. Store JSX in a variable

When a condition needs several lines, set a variable first:

App.jsx
JSX
function App() {
  const role = "admin";
  let panel = null;
  if (role === "admin") {
    panel = <p>You are an admin</p>;
  } else if (role === "editor") {
    panel = <p>You are an editor</p>;
  }
  return <div>{panel}</div>;
}

Not rendering vs hiding with CSS

{show && <Panel />} removes the component from the page, and it loses its state. Hiding with CSS (style={{ display: show ? "block" : "none" }}) keeps it mounted and keeps its state. Pick on purpose:

  • Not rendering: cheaper, resets state, nothing for screen readers to find.
  • CSS hiding: keeps state (for example text typed in a form), costs memory.

Common mistakes

  • {count && <X />} with a number. Use count > 0 &&.
  • Nested ternaries three levels deep. Switch to a lookup object or early returns.
  • Returning undefined. Forgetting return shows nothing and logs an error. Return null on purpose.
  • Changing the order of hooks inside a condition. Never call hooks conditionally; see Rules of Hooks.

Key points

  • Use if/early return, the ternary, && and lookup objects; it is all plain JavaScript.
  • Return null to render nothing.
  • Make && conditions real booleans.

Exercise: Show a warning only when the password is short

Make a password input. When the text is shorter than 8 characters (and not empty), show “Too short”. —solution

App.jsx
JSX
function App() {
  const [password, setPassword] = React.useState("");
  const tooShort = password.length > 0 && password.length < 8;

  return (
    <div>
      <label>
        Password <input aria-label="Password" type="text" value={password} onChange={(e) => setPassword(e.target.value)} />
      </label>
      {tooShort && <p style={{ color: "#c0392b" }}>Too short</p>}
    </div>
  );
}