Skip to main content

Conditional Rendering

Your components often need to display different content based on conditions. In React, you can conditionally render JSX using JavaScript syntax like if statements, &&, and ternary operators.

Conditionally Returning JSX

The simplest way to conditionally render is to return early:
function LoginMessage({ isLoggedIn, username }) {
  if (isLoggedIn) {
    return <h1>Welcome back, {username}!</h1>;
  }
  return <h1>Please sign in.</h1>;
}

Returning Nothing

Return null to render nothing:
function ErrorMessage({ error }) {
  if (!error) {
    return null; // Don't render anything
  }

  return (
    <div className="error">
      <strong>Error:</strong> {error}
    </div>
  );
}
Important: Returning null, undefined, true, or false from a component renders nothing. However, these values behave differently inside JSX expressions.

Ternary Operator

Use the ternary operator (? :) for inline conditional rendering:
function UserStatus({ isOnline }) {
  return (
    <div>
      <span className={isOnline ? 'status-online' : 'status-offline'}>
        {isOnline ? '🟢 Online' : '🔴 Offline'}
      </span>
    </div>
  );
}

Nested Ternaries

function Badge({ count }) {
  return (
    <div className="badge">
      {count === 0 
        ? 'No notifications'
        : count === 1
        ? '1 notification'
        : `${count} notifications`
      }
    </div>
  );
}
Readability tip: Deeply nested ternaries can be hard to read. Consider using if statements or extracting logic into a function if you have more than 2 levels.

Logical AND Operator (&&)

Use && to render something only when a condition is true:
function Notifications({ messages }) {
  return (
    <div>
      <h1>Inbox</h1>
      {messages.length > 0 && (
        <p>You have {messages.length} unread messages.</p>
      )}
    </div>
  );
}

How && Works in JSX

function Example({ show, count }) {
  return (
    <div>
      {/* ✅ Correct - renders "Hello" or nothing */}
      {show && <p>Hello</p>}

      {/* ❌ Wrong - renders 0 when count is 0! */}
      {count && <p>{count} items</p>}

      {/* ✅ Correct - explicit boolean check */}
      {count > 0 && <p>{count} items</p>}
    </div>
  );
}
Gotcha: The left side of && is rendered if it’s a falsy number like 0. Always use boolean conditions:
  • isReady && <Component />
  • count > 0 && <Component />
  • count && <Component /> (renders 0 when count is 0)

If/Else in JSX

You can’t use if/else directly in JSX, but you can use it before the return:
function Dashboard({ user }) {
  let content;
  
  if (user.role === 'admin') {
    content = <AdminPanel />;
  } else if (user.role === 'moderator') {
    content = <ModeratorPanel />;
  } else {
    content = <UserPanel />;
  }

  return (
    <div>
      <h1>Dashboard</h1>
      {content}
    </div>
  );
}

Using IIFE (Immediately Invoked Function Expression)

function StatusIcon({ status }) {
  return (
    <div>
      {(() => {
        switch (status) {
          case 'success':
            return <span>✅ Success</span>;
          case 'error':
            return <span>❌ Error</span>;
          case 'warning':
            return <span>⚠️ Warning</span>;
          default:
            return <span>ℹ️ Info</span>;
        }
      })()}
    </div>
  );
}

Multiple Conditions

Handle complex conditional logic with multiple conditions:
function MessageList({ messages, isLoading, error }) {
  if (error) {
    return <div className="error">Error: {error}</div>;
  }

  if (isLoading) {
    return <div className="loading">Loading messages...</div>;
  }

  if (messages.length === 0) {
    return <div className="empty">No messages yet.</div>;
  }

  return (
    <ul>
      {messages.map(message => (
        <li key={message.id}>{message.text}</li>
      ))}
    </ul>
  );
}

Conditional Attributes

Conditionally set element attributes:
function Button({ isPrimary, isDisabled, children }) {
  return (
    <button
      className={`btn ${isPrimary ? 'btn-primary' : 'btn-secondary'}`}
      disabled={isDisabled}
      aria-disabled={isDisabled ? 'true' : 'false'}
    >
      {children}
    </button>
  );
}

Conditional Class Names

function Card({ isActive, isHighlighted, hasError }) {
  const classNames = [
    'card',
    isActive && 'card-active',
    isHighlighted && 'card-highlighted',
    hasError && 'card-error'
  ].filter(Boolean).join(' ');

  return <div className={classNames}>Card content</div>;
}

// Or using template literals
function Card({ isActive, isHighlighted }) {
  return (
    <div className={`
      card
      ${isActive ? 'card-active' : ''}
      ${isHighlighted ? 'card-highlighted' : ''}
    `.trim()}>
      Card content
    </div>
  );
}

Extracting Conditional Logic

For complex conditions, extract into helper functions:
function canUserEdit(user, post) {
  return user.id === post.authorId || user.role === 'admin';
}

function canUserDelete(user, post) {
  return user.role === 'admin' || 
         (user.id === post.authorId && post.createdAt > Date.now() - 3600000);
}

function PostActions({ user, post }) {
  return (
    <div className="actions">
      {canUserEdit(user, post) && (
        <button>Edit</button>
      )}
      {canUserDelete(user, post) && (
        <button>Delete</button>
      )}
    </div>
  );
}

Conditional Rendering with State

Combine conditional rendering with state for interactive UIs:
import { useState } from 'react';

function Accordion({ title, children }) {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <div className="accordion">
      <button 
        onClick={() => setIsOpen(!isOpen)}
        className="accordion-header"
      >
        {title}
        <span>{isOpen ? '▼' : '▶'}</span>
      </button>
      
      {isOpen && (
        <div className="accordion-content">
          {children}
        </div>
      )}
    </div>
  );
}

Complete Authentication Example

1
Define component with multiple states
2
import { useState } from 'react';

function AuthPage() {
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState(null);
  const [user, setUser] = useState(null);
3
Handle authentication logic
4
  const handleLogin = async (credentials) => {
    setIsLoading(true);
    setError(null);
    
    try {
      const response = await fetch('/api/login', {
        method: 'POST',
        body: JSON.stringify(credentials)
      });
      
      if (!response.ok) throw new Error('Login failed');
      
      const userData = await response.json();
      setUser(userData);
      setIsLoggedIn(true);
    } catch (err) {
      setError(err.message);
    } finally {
      setIsLoading(false);
    }
  };
5
Render conditionally based on state
6
  // Show loading state
  if (isLoading) {
    return (
      <div className="auth-page">
        <div className="spinner">Loading...</div>
      </div>
    );
  }

  // Show logged in state
  if (isLoggedIn && user) {
    return (
      <div className="auth-page">
        <h1>Welcome, {user.name}!</h1>
        <p>Email: {user.email}</p>
        {user.isAdmin && (
          <div className="admin-badge">Admin Access</div>
        )}
        <button onClick={() => setIsLoggedIn(false)}>
          Logout
        </button>
      </div>
    );
  }

  // Show login form
  return (
    <div className="auth-page">
      <h1>Login</h1>
      {error && (
        <div className="error-message">{error}</div>
      )}
      <LoginForm onSubmit={handleLogin} />
    </div>
  );
}

Pattern Comparison

Choose the right pattern for your use case:
function ComparisonExample({ show, count, status }) {
  return (
    <div>
      {/* Early return - best for component-level conditions */}
      {!show && null}

      {/* Ternary - best for either/or scenarios */}
      {status === 'active' ? <ActiveBadge /> : <InactiveBadge />}

      {/* && operator - best for showing/hiding single elements */}
      {count > 0 && <NotificationBadge count={count} />}

      {/* Variable assignment - best for complex multi-condition logic */}
      {(() => {
        let content;
        if (status === 'loading') content = <Spinner />;
        else if (status === 'error') content = <ErrorMessage />;
        else content = <DataDisplay />;
        return content;
      })()}
    </div>
  );
}

Best Practices

Guidelines for conditional rendering:
  • Use early returns for component-level conditions
  • Use && for simple show/hide logic (with boolean conditions)
  • Use ternary for either/or scenarios
  • Extract complex conditions into helper functions
  • Avoid deeply nested ternaries
  • Be careful with falsy values (especially 0) with &&

Next Steps

Now that you can conditionally render UI, learn how to render lists of data efficiently.