Introduction to Conditional Rendering
Conditional rendering in React means displaying different elements or components depending on the current state, props, or other conditions. It allows an interface to respond to user interactions, authentication status, loading progress, permissions, and the availability of data.
React uses JavaScript expressions to determine what a component returns. You can use familiar JavaScript constructs such as if, the ternary operator, logical AND (&&), and switch statements to decide which UI should appear.
Using if Statements
An if statement is useful when a component needs to return completely different content based on a condition. Evaluate the condition before the main JSX and return the appropriate component or element.
function Greeting({ isLoggedIn }) {
if (isLoggedIn) {
return <h2>Welcome back!</h2>;
}
return <h2>Please sign in.</h2>;
}
export default Greeting;
When isLoggedIn is true, React renders the welcome message. Otherwise, it renders the sign-in message. Early returns can make more complicated components easier to read by handling special cases first.
Using the Ternary Operator
The ternary operator is a concise way to choose between two expressions directly inside JSX. It is particularly useful for short conditional elements.
function AccountStatus({ isActive }) {
return (
<div>
<p>
{isActive ? 'Account active' : 'Account inactive'}
</p>
{isActive ? (
<button>Open dashboard</button>
) : (
<button>Activate account</button>
)}
</div>
);
}
export default AccountStatus;
The expression before the question mark is evaluated as the condition. The expression before the colon is selected when the condition is truthy, and the expression after the colon is selected otherwise.
Avoid deeply nested ternary operators because they can make UI logic difficult to follow. For several distinct states, consider using an if statement or a switch statement instead.
Using Logical AND
The logical AND operator is useful when an element should appear only if a condition is true. If the left operand is falsy, JavaScript returns that operand; otherwise, it evaluates and returns the right operand.
function Notification({ hasMessage }) {
return (
<div>
<h2>Notifications</h2>
{hasMessage && (
<p>You have a new notification.</p>
)}
</div>
);
}
export default Notification;
When hasMessage is true, React renders the paragraph. When it is false, the expression evaluates to false and React renders nothing for that expression.
Be careful when the condition is a number. An expression such as count && <p>Items available</p> can render the number 0 when count is zero. If zero should display nothing, use an explicit comparison such as count > 0 && ....
Using a Switch Statement
A switch statement works well when the UI depends on several possible values, such as request status, subscription level, or the current step in a workflow. Put the statement in a function and return the corresponding JSX.
function OrderStatus({ status }) {
switch (status) {
case 'pending':
return <p>Your order is being processed.</p>;
case 'shipped':
return <p>Your order is on its way.</p>;
case 'delivered':
return <p>Your order has arrived.</p>;
default:
return <p>Order status unavailable.</p>;
}
}
export default OrderStatus;
Each case handles a distinct state, and the default branch provides a fallback for values that are not recognized. Returning from each case avoids accidental fall-through and makes the result explicit.
Conditional Rendering with Early Returns
Early returns are especially useful when a component has loading, error, empty, and success states. Handling these states before the main content keeps the normal rendering path straightforward.
function ProductDetails({ product, loading, error }) {
if (loading) {
return <p>Loading product...</p>;
}
if (error) {
return <p role="alert">Unable to load product.</p>;
}
if (!product) {
return <p>Product not found.</p>;
}
return (
<article>
<h2>{product.name}</h2>
<p>Price: {product.price}</p>
</article>
);
}
export default ProductDetails;
Each early return handles one distinct state, leaving the final JSX for the successful case. This pattern is common in dashboards, detail pages, search results, and API-driven components.
See React API Fetching for examples of managing asynchronous data.
Rendering Based on User Permissions
Conditional rendering can adapt an interface to the current user's role or permissions. For example, an administrative action may be shown only to users whose role allows it.
function DashboardActions({ role }) {
return (
<div>
<button>View profile</button>
{role === 'admin' && (
<button>Manage users</button>
)}
</div>
);
}
export default DashboardActions;
This example changes what appears in the UI, but it does not enforce security. The backend must independently verify the user's permissions before performing sensitive operations. Client-side conditions can always be bypassed or modified by a user.
Combining Multiple Conditions
JavaScript logical operators can combine conditions when rendering depends on more than one value. Use parentheses to make the intended logic clear, particularly when combining AND (&&) and OR (||).
function CourseAccess({ isLoggedIn, hasSubscription }) {
const canAccess = isLoggedIn && hasSubscription;
return (
<section>
{canAccess ? (
<p>You can access this course.</p>
) : (
<p>Sign in and subscribe to continue.</p>
)}
</section>
);
}
export default CourseAccess;
Naming a meaningful condition such as canAccess makes the JSX easier to understand. It also allows the same condition to be reused consistently in the component.
Showing and Hiding Elements
You can conditionally include an element in the render output or keep it mounted and change its visibility. These approaches have different effects on component state, accessibility, and layout.
Conditionally include an element
{isOpen && <div>Panel content</div>}
When isOpen becomes false, the panel is removed from the React tree. Components inside it may unmount and lose their local state.
Keep an element mounted and change visibility
<div hidden={!isOpen}>
Panel content
</div>
The element remains in the DOM while the hidden attribute controls its visibility. Its descendant components remain mounted, so their local state is generally preserved. Choose the approach that matches the required behavior and accessibility needs.
Conditional Rendering with Lists
A component can render a list when data exists and display a fallback message when the list is empty. This provides a better experience than showing a blank area without explanation.
function CourseList({ courses }) {
if (courses.length === 0) {
return <p>No courses are available.</p>;
}
return (
<ul>
{courses.map((course) => (
<li key={course.id}>{course.title}</li>
))}
</ul>
);
}
export default CourseList;
The example assumes courses is always an array. If the data might not have loaded yet, represent that state separately or provide a suitable default. Each item also needs a stable key so React can track list entries across updates.
Learn more about list rendering and stable keys in React Lists and Keys.
Using Conditional Rendering with State
State lets a component change what it renders in response to user interactions. A common example is a toggle button that shows or hides additional information.
import { useState } from 'react';
function DetailsPanel() {
const [isVisible, setIsVisible] = useState(false);
return (
<section>
<button
type="button"
aria-expanded={isVisible}
onClick={() => setIsVisible((current) => !current)}
>
{isVisible ? 'Hide details' : 'Show details'}
</button>
{isVisible && (
<div>
<h2>Additional information</h2>
<p>This content appears when the panel is open.</p>
</div>
)}
</section>
);
}
export default DetailsPanel;
The functional state update uses the previous value to calculate the next value. The aria-expanded attribute communicates the current expanded state to assistive technologies.
Explore React State to understand how state updates cause components to render again.
Common Conditional Rendering Mistakes
Rendering zero with logical AND
Expressions such as items.length && ... can render the number zero when the list is empty. Use items.length > 0 && ... to make the intended condition explicit.
Nesting too many ternary operators
Long chains of nested ternaries make conditions difficult to understand and maintain. Extract complex logic into variables, helper functions, or early returns.
Confusing hidden content with removed content
Removing a component can reset its local state, while hiding a mounted element generally preserves that state. Choose based on whether the component should remain active.
Using UI conditions as access control
Hiding an administrative button is not a security boundary. Always enforce permissions in the backend for protected data and operations.
Ignoring loading and error states
Data-driven interfaces should distinguish loading, success, empty, and failure states instead of treating missing data as a single condition.
Choosing the Right Technique
| Technique | Best suited for |
|---|---|
if statement |
Early returns and larger conditional branches. |
| Ternary operator | Choosing between two expressions inside JSX. |
| Logical AND | Displaying an element only when a condition is true. |
switch statement |
Handling several distinct status or category values. |
| Early return | Separating loading, error, empty, and success states. |
Key Takeaway
Conditional rendering lets React interfaces respond to data, state, props, and user permissions. Use the simplest JavaScript technique that makes each condition clear, handle loading and error states explicitly, and remember that hiding UI elements does not replace server-side security checks.