React Tutorial 0/120 lessons ~6 min read Lesson 22

    Conditional Rendering

    Conditional rendering in React: use if, early returns, ternaries, &&, ||, ??, null, and UI states like loading, error, empty, and success.

    Course progress0%
    Focus
    55 guided sections
    Practice signal
    Examples included
    Career prep
    Interview Q&A included

    Conditional Rendering

    Conditional Rendering is the technique of displaying different UI based on a condition.

    In React, you use normal JavaScript conditions to decide what should appear in the UI.

    tsx
    function Greeting({ isLoggedIn }: { isLoggedIn: boolean }) {
    if (isLoggedIn) {
    return <h1>Welcome back!</h1>;
    }
    return <h1>Please log in.</h1>;
    }

    If isLoggedIn is true:

    text
    Welcome back!

    If it is false:

    text
    Please log in.

    The fundamental idea is:

    text
    Condition
    ↓
    Choose UI
    ↓
    React renders the result

    Learning Objectives

    By the end of this lesson, you will understand:

    1. What conditional rendering is
    2. Using if statements and early returns
    3. Ternary operators
    4. Logical &&, ||, and ??
    5. Rendering nothing with null
    6. Conditional attributes, text, and classes
    7. Loading, error, empty, and success states
    8. Common mistakes and best practices
    9. Interview questions for conditional rendering

    1. What Is Conditional Rendering?

    A React component doesn't always need to render the same UI.

    text
    User logged in?
    │
    ┌───┴───┐
    Yes No
    │ │
    ▼ ▼
    Dashboard Login

    React allows you to express this directly in JavaScript.

    2. The Simplest Example

    tsx
    function UserStatus({ isLoggedIn }: { isLoggedIn: boolean }) {
    if (isLoggedIn) {
    return <p>Welcome!</p>;
    }
    return <p>Please log in.</p>;
    }
    <UserStatus isLoggedIn={true} /> // Welcome!
    <UserStatus isLoggedIn={false} /> // Please log in.

    3. Conditional Rendering with if

    The normal JavaScript if statement works well when UI branches are substantially different.

    tsx
    function Dashboard({ isAdmin }: { isAdmin: boolean }) {
    if (isAdmin) {
    return <AdminDashboard />;
    }
    return <UserDashboard />;
    }

    This is often clearer than forcing everything into JSX.

    4. Early Returns

    A very common React pattern is the early return.

    tsx
    function Profile({ user }: { user: { name: string; email: string } | null }) {
    if (!user) {
    return <p>Please log in.</p>;
    }
    return (
    <div>
    <h1>{user.name}</h1>
    <p>{user.email}</p>
    </div>
    );
    }
    text
    user exists?
    │
    ┌───┴───┐
    No Yes
    │ │
    ▼ ▼
    Login Profile

    Early returns make components easier to read.

    5. Multiple Conditions with if

    tsx
    function Dashboard({ role }: { role: string }) {
    if (role === "admin") {
    return <AdminDashboard />;
    }
    if (role === "manager") {
    return <ManagerDashboard />;
    }
    if (role === "user") {
    return <UserDashboard />;
    }
    return <NotFound />;
    }

    This is often clearer than deeply nested ternary expressions.

    6. Ternary Operator

    For simple conditions, use the JavaScript ternary operator:

    text
    condition
    ? valueIfTrue
    : valueIfFalse
    tsx
    function Greeting({ isLoggedIn }: { isLoggedIn: boolean }) {
    return (
    <h1>
    {isLoggedIn ? "Welcome back!" : "Please log in"}
    </h1>
    );
    }

    7. Ternary with Components

    tsx
    function App({ isLoggedIn }: { isLoggedIn: boolean }) {
    return (
    <>
    {isLoggedIn ? <Dashboard /> : <Login />}
    </>
    );
    }

    This is very common in React.

    8. Ternary with JSX Blocks

    tsx
    function Account({ isLoggedIn }: { isLoggedIn: boolean }) {
    return (
    <section>
    {isLoggedIn ? (
    <div>
    <h1>My Account</h1>
    <p>Welcome back.</p>
    <button>Logout</button>
    </div>
    ) : (
    <div>
    <h1>Guest</h1>
    <p>Please log in.</p>
    <button>Login</button>
    </div>
    )}
    </section>
    );
    }

    9. When Should You Use if vs Ternary?

    Use if when:

    • Branches are large
    • There are multiple conditions
    • You want early returns
    • The logic is easier to read outside JSX

    Use a ternary when:

    • There are two simple alternatives
    • The condition belongs naturally inside the JSX
    tsx
    // Good
    if (!user) {
    return <Login />;
    }
    // Good
    <p>{isOnline ? "Online" : "Offline"}</p>

    10. Logical AND &&

    Another very common React pattern is:

    tsx
    {condition && <Component />}
    tsx
    function Notifications({ hasNotifications }: { hasNotifications: boolean }) {
    return (
    <div>
    {hasNotifications && <NotificationBadge />}
    </div>
    );
    }

    If hasNotifications is true, the badge appears. If false, it doesn't.

    11. Why Does && Work?

    JavaScript evaluates true && value as value, and false && value as false.

    React doesn't render false as visible UI.

    tsx
    {isLoggedIn && <Dashboard />}
    // Render Dashboard only when isLoggedIn is truthy.

    12. Example: Show a Logout Button

    tsx
    function Header({ isLoggedIn }: { isLoggedIn: boolean }) {
    return (
    <header>
    <h1>My Website</h1>
    {isLoggedIn && <button>Logout</button>}
    </header>
    );
    }

    13. && Is Best for One-Sided Conditions

    Use {isAdmin && <AdminPanel />} when you mean: show this if the condition is true.

    If you need true → A and false → B, use a ternary:

    tsx
    {isAdmin ? <AdminPanel /> : <UserPanel />}

    14. Important && Pitfall: Numbers

    Be careful with:

    tsx
    {count && <p>Messages available</p>}

    If count = 0, the expression evaluates to 0, and React can render the 0.

    Instead, use an explicit comparison:

    tsx
    {count > 0 && <p>Messages available</p>}

    This is an important React conditional-rendering rule.

    15. Logical OR ||

    tsx
    function Greeting({ name }: { name?: string }) {
    return <h1>Hello, {name || "Guest"}</h1>;
    }

    If name is missing or falsy, "Guest" is used.

    Remember || treats false, 0, "", null, undefined, and NaN as falsy.

    16. Nullish Coalescing ??

    Sometimes ?? is better than ||.

    tsx
    function Price({ price }: { price?: number | null }) {
    return <p>Price: {price ?? "Not available"}</p>;
    }

    With price = 0, the value 0 is preserved. price || "Not available" would treat 0 as falsy. ?? only falls back for null and undefined.

    17. Rendering Nothing

    Sometimes the correct UI is nothing.

    tsx
    function AdminPanel({ isAdmin }: { isAdmin: boolean }) {
    if (!isAdmin) {
    return null;
    }
    return (
    <section>
    <h2>Admin Panel</h2>
    </section>
    );
    }

    Non-admin users don't get any visible output from this component.

    18. Conditional Rendering with State

    tsx
    import { useState } from "react";
    function Toggle() {
    const [isOpen, setIsOpen] = useState(false);
    return (
    <div>
    <button onClick={() => setIsOpen(!isOpen)}>Toggle</button>
    {isOpen && <p>The content is visible.</p>}
    </div>
    );
    }
    text
    isOpen = false
    ↓
    content hidden
    ↓
    user clicks
    ↓
    setIsOpen(true)
    ↓
    component re-renders
    ↓
    content appears

    19. Conditional Rendering with Props

    tsx
    function Button({
    isDisabled,
    children,
    }: {
    isDisabled?: boolean;
    children: React.ReactNode;
    }) {
    return <button disabled={isDisabled}>{children}</button>;
    }
    <Button isDisabled>Save</Button>

    20. Conditional Attributes

    tsx
    function SubmitButton({ isLoading }: { isLoading: boolean }) {
    return <button disabled={isLoading}>Submit</button>;
    }

    If isLoading = true, the button is disabled.

    21. Conditional Text

    tsx
    function Button({ isLoading }: { isLoading: boolean }) {
    return <button>{isLoading ? "Saving..." : "Save"}</button>;
    }

    22. Conditional Classes

    tsx
    function Status({ isActive }: { isActive: boolean }) {
    return (
    <span className={isActive ? "status active" : "status inactive"}>
    {isActive ? "Active" : "Inactive"}
    </span>
    );
    }

    23. Conditional Classes with Template Literals

    tsx
    function Button({ variant }: { variant: string }) {
    return <button className={`button ${variant}`}>Save</button>;
    }
    <Button variant="primary" />
    <Button variant="danger" />

    24. Conditional Components

    tsx
    function Page({ isLoggedIn }: { isLoggedIn: boolean }) {
    if (isLoggedIn) {
    return <Dashboard />;
    }
    return <Login />;
    }
    function PageAlt({ isAdmin }: { isAdmin: boolean }) {
    return <>{isAdmin ? <AdminDashboard /> : <UserDashboard />}</>;
    }

    25. Loading States

    tsx
    function ProductList({
    isLoading,
    products,
    }: {
    isLoading: boolean;
    products: { id: number; name: string }[];
    }) {
    if (isLoading) {
    return <p>Loading products...</p>;
    }
    return (
    <ul>
    {products.map((product) => (
    <li key={product.id}>{product.name}</li>
    ))}
    </ul>
    );
    }
    text
    Loading → Loading message
    Loaded → Product list

    26. Loading + Error + Success

    tsx
    function Products({
    isLoading,
    error,
    products,
    }: {
    isLoading: boolean;
    error?: string | null;
    products: { id: number; name: string }[];
    }) {
    if (isLoading) {
    return <p>Loading...</p>;
    }
    if (error) {
    return <p>Unable to load products.</p>;
    }
    return (
    <ul>
    {products.map((product) => (
    <li key={product.id}>{product.name}</li>
    ))}
    </ul>
    );
    }
    text
    Products
    │
    ┌────────┼────────┐
    ↓ ↓ ↓
    Loading Error Success
    ↓ ↓ ↓
    Spinner Message List

    This pattern appears everywhere in React applications.

    27. Empty States

    tsx
    function ProductList({ products }: { products: { id: number; name: string }[] }) {
    if (products.length === 0) {
    return <p>No products found.</p>;
    }
    return (
    <ul>
    {products.map((product) => (
    <li key={product.id}>{product.name}</li>
    ))}
    </ul>
    );
    }

    This gives you Loading, Error, Empty, and Success as separate UI states.

    28. Authentication Example

    tsx
    function App({ user }: { user: unknown }) {
    if (!user) {
    return <LoginPage />;
    }
    return <Dashboard user={user} />;
    }

    29. Permission Example

    tsx
    function Settings({ user }: { user: { isAdmin: boolean } }) {
    return (
    <section>
    <h1>Settings</h1>
    {user.isAdmin && <AdminSettings />}
    </section>
    );
    }

    30. Multiple Conditions with Ternaries

    You can technically write nested ternaries, but they quickly become hard to read.

    tsx
    function Status({ status }: { status: string }) {
    return (
    <p>
    {status === "loading"
    ? "Loading..."
    : status === "error"
    ? "Something went wrong."
    : "Success!"}
    </p>
    );
    }

    For multiple states, prefer clearer logic.

    31. Better Alternative: Early Returns

    tsx
    function Status({ status }: { status: string }) {
    if (status === "loading") {
    return <p>Loading...</p>;
    }
    if (status === "error") {
    return <p>Something went wrong.</p>;
    }
    return <p>Success!</p>;
    }

    32. Multiple Conditions Inside JSX

    tsx
    function Dashboard({
    isLoggedIn,
    isAdmin,
    }: {
    isLoggedIn: boolean;
    isAdmin: boolean;
    }) {
    return (
    <main>
    {isLoggedIn && <UserMenu />}
    {isLoggedIn && isAdmin && <AdminPanel />}
    </main>
    );
    }

    33. Conditional Rendering with Functions

    tsx
    function getStatusMessage(status: string) {
    if (status === "loading") return "Loading...";
    if (status === "error") return "Something went wrong.";
    return "Ready";
    }
    function Status({ status }: { status: string }) {
    return <p>{getStatusMessage(status)}</p>;
    }

    34. Conditional Rendering with Variables

    tsx
    function UserProfile({ user }: { user: unknown }) {
    let content;
    if (!user) {
    content = <Login />;
    } else {
    content = <Profile user={user} />;
    }
    return <main>{content}</main>;
    }

    35. Conditional Rendering with switch

    tsx
    function Status({ status }: { status: string }) {
    switch (status) {
    case "loading":
    return <Loading />;
    case "error":
    return <ErrorMessage />;
    case "empty":
    return <EmptyState />;
    case "success":
    return <Success />;
    default:
    return <UnknownState />;
    }
    }

    36. Conditional Rendering Is Just JavaScript

    React doesn't have a completely separate conditional syntax.

    You use JavaScript (if, ternary, &&, ||, ??, switch, variables, functions) to determine what JSX should be returned.

    text
    JavaScript condition
    ↓
    Choose React element(s)
    ↓
    React renders them

    37. Conditional Rendering and Component State

    tsx
    const [isLoggedIn, setIsLoggedIn] = useState(false);
    return <>{isLoggedIn ? <Dashboard /> : <Login />}</>;
    // Later:
    setIsLoggedIn(true);
    // → isLoggedIn = true → Dashboard

    38. Conditional Rendering with Forms

    tsx
    function LoginForm({ isSubmitted }: { isSubmitted: boolean }) {
    if (isSubmitted) {
    return <p>Login successful!</p>;
    }
    return <form>{/* form fields */}</form>;
    }

    39. Conditional Rendering with Permissions

    tsx
    function Protected({
    allowed,
    children,
    }: {
    allowed: boolean;
    children: React.ReactNode;
    }) {
    if (!allowed) {
    return null;
    }
    return children;
    }
    <Protected allowed={user.isAdmin}>
    <AdminPanel />
    </Protected>

    This is composition + props + conditional rendering.

    40. Conditional Rendering with Feature Flags

    tsx
    function HomePage({ newDashboardEnabled }: { newDashboardEnabled: boolean }) {
    return <>{newDashboardEnabled ? <NewDashboard /> : <OldDashboard />}</>;
    }

    41. Conditional Rendering and Accessibility

    Don't simply hide UI with CSS when the element should not exist in the interface.

    tsx
    {isLoggedIn && <LogoutButton />}

    is different from rendering the button and merely hiding it visually. Conditional rendering should reflect whether an element should actually participate in the UI.

    42-48. Common Mistakes

    Nested ternaries

    Avoid deeply nested ternaries. Prefer early returns or extracted functions.

    Misusing &&

    tsx
    // Bad when length can be 0
    {items.length && <List />}
    // Prefer
    {items.length > 0 && <List />}

    Confusing || with ??

    tsx
    {count || "No count"} // 0 becomes "No count"
    {count ?? "No count"} // 0 is preserved

    Hiding logic in JSX

    Extract complex conditions into variables or functions.

    Mixing too many responsibilities

    Extract meaningful components so conditional rendering stays clear.

    Forgetting loading / empty states

    Consider Loading, Error, Empty, and Success separately.

    Treating all conditions the same

    Match the pattern to the situation: ternary, &&, if, or switch.

    49. Best Practices

    1. Prefer simple conditions.
    2. Use early returns for major UI branches.
    3. Use ternaries for simple two-way choices.
    4. Use && for one-sided rendering.
    5. Be careful with 0 and &&.
    6. Use ?? when 0 or "" should remain valid.
    7. Avoid deeply nested ternaries.
    8. Extract complex conditions into variables or functions.
    9. Handle loading, error, empty, and success states.
    10. Keep conditional logic readable.
    11. Use components to isolate complex UI states.
    12. Don't introduce unnecessary abstraction.

    50. Complete Example: Product Page

    tsx
    function ProductPage({
    isLoading,
    error,
    product,
    }: {
    isLoading: boolean;
    error?: string | null;
    product?: { name: string; price: number; inStock: boolean; isFeatured?: boolean } | null;
    }) {
    if (isLoading) {
    return <p>Loading product...</p>;
    }
    if (error) {
    return <p>Unable to load product.</p>;
    }
    if (!product) {
    return <p>Product not found.</p>;
    }
    return (
    <article>
    <h1>{product.name}</h1>
    <p>INR {product.price}</p>
    {product.inStock ? (
    <button>Add to Cart</button>
    ) : (
    <p>Currently unavailable</p>
    )}
    {product.isFeatured && <span>Featured Product</span>}
    </article>
    );
    }

    51. Complete Example: Authentication

    tsx
    function App({ user }: { user?: { isAdmin?: boolean } | null }) {
    if (!user) {
    return <LoginPage />;
    }
    return (
    <main>
    <Navbar user={user} />
    <Dashboard user={user} />
    {user.isAdmin && <AdminPanel />}
    </main>
    );
    }

    52. Complete Example: Shopping Cart

    tsx
    function Cart({ items }: { items: { id: number; name: string; price: number }[] }) {
    if (items.length === 0) {
    return (
    <section>
    <h2>Your Cart</h2>
    <p>Your cart is empty.</p>
    </section>
    );
    }
    return (
    <section>
    <h2>Your Cart</h2>
    {items.map((item) => (
    <div key={item.id}>
    <h3>{item.name}</h3>
    <p>INR {item.price}</p>
    </div>
    ))}
    <button>Checkout</button>
    </section>
    );
    }

    53. Complete Example: Status Component

    tsx
    function StatusMessage({ status }: { status: string }) {
    if (status === "loading") return <Loading />;
    if (status === "error") return <ErrorMessage />;
    if (status === "empty") return <EmptyState />;
    if (status === "success") return <SuccessMessage />;
    return <p>Unknown status.</p>;
    }

    54-55. Practical Exercises

    Exercise 1: UserStatus

    Receive isLoggedIn and isAdmin. Show "Please log in", "Welcome User", or "Welcome Admin".

    tsx
    function UserStatus({
    isLoggedIn,
    isAdmin,
    }: {
    isLoggedIn: boolean;
    isAdmin: boolean;
    }) {
    if (!isLoggedIn) {
    return <p>Please log in</p>;
    }
    if (isAdmin) {
    return <p>Welcome Admin</p>;
    }
    return <p>Welcome User</p>;
    }

    Exercise 2: ProductList states

    Handle loading, error, empty, and success for a product list.

    tsx
    function ProductList({
    isLoading,
    error,
    products,
    }: {
    isLoading: boolean;
    error?: string | null;
    products: { id: number; name: string }[];
    }) {
    if (isLoading) return <p>Loading products...</p>;
    if (error) return <p>Unable to load products.</p>;
    if (products.length === 0) return <p>No products found.</p>;
    return (
    <ul>
    {products.map((product) => (
    <li key={product.id}>{product.name}</li>
    ))}
    </ul>
    );
    }

    56. Interview Questions

    Q1. What is conditional rendering in React?

    Rendering different React elements or components depending on application state, props, or other conditions, using normal JavaScript constructs.

    Q2. How do you conditionally render a component?

    tsx
    if (isLoggedIn) return <Dashboard />;
    {isLoggedIn ? <Dashboard /> : <Login />}
    {isAdmin && <AdminPanel />}

    Q3. When should you use a ternary?

    When there are two relatively simple UI alternatives.

    Q4. When should you use &&?

    When you want to render something only when a condition is truthy and need no alternative UI.

    Q5. What is the problem with {count && <Component />}?

    If count is 0, React can render 0. Prefer {count > 0 && <Component />}.

    Q6. How do you render nothing in React?

    Return null.

    Q7. Can conditional rendering depend on props?

    Yes. Props commonly drive which UI branch appears.

    Q8. Can conditional rendering depend on state?

    Yes. Updating state causes React to render the appropriate UI again.

    57. The Three Most Important Patterns

    Pattern 1 — if

    tsx
    if (!user) {
    return <Login />;
    }
    return <Dashboard />;

    Pattern 2 — Ternary

    tsx
    {isOnline ? "Online" : "Offline"}

    Pattern 3 — &&

    tsx
    {isAdmin && <AdminPanel />}

    Master these three and you'll handle most everyday conditional rendering.

    58. Conditional Rendering Mental Model

    text
    Props
    +
    State
    │
    ▼
    Condition(s)
    │
    ┌───────┼───────┐
    ▼ ▼ ▼
    Loading Error Success
    │ │ │
    ▼ ▼ ▼
    Loading Error Data
    UI UI UI

    You express the conditions, and React renders the resulting UI.

    59. Final Cheat Sheet

    tsx
    // if
    if (!user) return <Login />;
    // ternary
    {isLoggedIn ? <Dashboard /> : <Login />}
    // &&
    {isAdmin && <AdminPanel />}
    // ||
    {name || "Guest"}
    // ??
    {price ?? "Not available"}
    // nothing
    return null;
    // attribute
    <button disabled={isLoading}>
    // text
    {isLoading ? "Saving..." : "Save"}
    // class
    className={isActive ? "active" : "inactive"}
    // multiple states
    if (isLoading) return <Loading />;
    if (error) return <Error />;
    if (!items.length) return <Empty />;
    return <List items={items} />;

    Key Takeaway

    Conditional rendering allows React components to adapt their UI to changing data, props, and state.

    text
    if
    ↓
    Major UI branches
    ternary
    ↓
    Two alternatives
    &&
    ↓
    Optional UI
    null
    ↓
    Render nothing

    And in a real application, think in terms of UI states:

    text
    Loading
    ↓
    Error
    ↓
    Empty
    ↓
    Success

    A strong React developer doesn't just ask "What should this component render?" They also ask: "What UI should the user see in every possible state of this component?"

    That mindset leads naturally into the next major React concepts: Rendering Lists, Handling Events, and Managing State.

    Ready to mark this lesson complete?Track your journey across the entire course.