Conditional Rendering in React Apps
Simplifying React with &&, Ternary, and Early Return Techniques

In simple term, it is used to render or show UI elements / Components based on condition.
Conditional rendering in React is the process of displaying different UI elements or components based on specific conditions, such as the application's state, user roles, or input data. It uses standard JavaScript logic and syntax to dynamically control what is rendered to the user.
There are many ways to implement conditional rendering, each one has specific use case. Developers can use several JavaScript techniques to implement conditional rendering in React components:
| Technique | Description | Use Case |
if statements | Use standard if or if-else blocks outside of the return statement in a functional component to decide which JSX to return. This is ideal for early returns or complex logic. | Displaying a login form or a user dashboard depending on an isLoggedIn state. |
Ternary Operator (? :) | A concise inline if-else statement within JSX. It is used when you need to render one of two possible outcomes. | Toggling button text between "Login" and "Logout" based on a boolean isLoggedIn variable. |
Logical && Operator | Renders the element on the right side if the condition on the left side is true; otherwise, it renders nothing (null). This is known as short-circuit evaluation. | Showing a notification message only if there are unread messages (messageCount > 0 && <Notification />). |
| Element Variables | Assign JSX to a variable within the component logic and then include the variable in the main return statement. | A cleaner way to handle slightly more complex conditional logic while keeping the return block simple. |
switch statements | Useful for handling multiple possible conditions in a readable manner. Like if-else statements, they are typically used outside the main return to define a variable holding the output. | Rendering different components based on a userRole (e.g., 'viewer', 'editor', 'admin'). |
Detailed Example of each Technique
These examples are based on production-grade standards.
1. Logical AND (&&) Operator
Use case: Show optional UI elements that depend on a single condition
function NotificationBadge({ unreadCount }) {
return (
<div className="nav-item">
<BellIcon />
{unreadCount > 0 && (
<span className="badge">{unreadCount}</span>
)}
</div>
);
}
Why this pattern: Perfect when you want to render something or nothing. If unreadCount is 0, the badge doesn't appear at all.
Production tip: Be careful with falsy values. {count && <Badge />} will render "0" on screen if count is 0. Use {count > 0 && <Badge />} instead. And you don’t want to show that.
2. Ternary Operator (? :)
Use case: Toggle between two different UI states
function SubscribeButton({ isSubscribed, onToggle }) {
return (
<button
onClick={onToggle}
className={isSubscribed ? "btn-secondary" : "btn-primary"}
>
{isSubscribed ? "Unsubscribe" : "Subscribe"}
</button>
);
}
Why this pattern: When you need to show one thing or another (not nothing). Both states always render something.
Production tip: Keep ternaries simple. If the JSX gets complex, extract to variables or use early returns instead.
3. Early Return
Use case: Handle loading/error states before rendering main content. When you want to show skeleton loader while fetching and processing data.
function UserProfile({ userId }) {
const { data, isLoading, error } = useUser(userId);
if (isLoading) {
return <Spinner />;
}
if (error) {
return <ErrorMessage error={error} />;
}
if (!data) {
return <EmptyState message="User not found" />;
}
// Main rendering logic - clean and focused
return (
<div className="profile">
<Avatar src={data.avatar} />
<h1>{data.name}</h1>
<Bio text={data.bio} />
</div>
);
}
Why this pattern: Keeps your main component logic clean by handling edge cases first. No deeply nested ternaries or complex conditionals.
Production tip: This is the most maintainable pattern for components with multiple states (loading, error, empty, success). Always handle edge cases at the top.
4. if Statements
Use case: There is multiple conditions with default state. Show components based on conditions. For example same component has different version. Render it based on version.
function Dashboard({ user, permissions }) {
let content;
if (!user) {
content = <LoginPrompt />;
} else if (!user.emailVerified) {
content = <EmailVerificationRequired email={user.email} />;
} else if (user.subscription === 'expired') {
content = <SubscriptionExpiredNotice />;
} else {
content = <DashboardContent user={user} permissions={permissions} />;
}
return (
<div className="dashboard-container">
<Header user={user} />
{content}
</div>
);
}
Why this pattern: When you have multiple else-if conditions, it's cleaner to handle them before the return statement rather than nesting ternaries.
Production tip: Use this when logic is too complex for ternaries but doesn't require early returns.
5. Element Variables
Use case: Building dynamic UI elements based on data state. Define elements using JavaScript variables.
function OrderStatus({ order }) {
// Define UI elements based on order status
let statusBadge;
let actionButton;
if (order.status === 'pending') {
statusBadge = <Badge color="yellow">Pending Payment</Badge>;
actionButton = <button>Complete Payment</button>;
} else if (order.status === 'processing') {
statusBadge = <Badge color="blue">Processing</Badge>;
actionButton = <button disabled>Preparing Order...</button>;
} else if (order.status === 'shipped') {
statusBadge = <Badge color="green">Shipped</Badge>;
actionButton = <button>Track Package</button>;
} else {
statusBadge = <Badge color="gray">Delivered</Badge>;
actionButton = <button>Leave Review</button>;
}
return (
<div className="order-card">
<h3>Order #{order.id}</h3>
{statusBadge}
<div className="order-items">
{order.items.map(item => <OrderItem key={item.id} {...item} />)}
</div>
<div className="order-total">${order.total}</div>
{actionButton}
</div>
);
}
Why this pattern: Keeps your return statement clean and readable while handling conditional logic for multiple related elements.
Production tip: Great for when multiple parts of your UI change together based on the same condition.
6. switch Statements
Use case: Role-based access control and rendering different admin panels
function AdminPanel({ userRole, userData }) {
let panelContent;
switch (userRole) {
case 'viewer':
panelContent = (
<div className="viewer-panel">
<h2>Viewer Dashboard</h2>
<ReportsList reports={userData.reports} readOnly />
<p className="permission-note">
You have read-only access. Contact admin for more permissions.
</p>
</div>
);
break;
case 'editor':
panelContent = (
<div className="editor-panel">
<h2>Editor Dashboard</h2>
<ReportsList reports={userData.reports} />
<CreateReportButton />
<EditHistoryLog entries={userData.editHistory} />
</div>
);
break;
case 'admin':
panelContent = (
<div className="admin-panel">
<h2>Admin Dashboard</h2>
<UserManagement users={userData.allUsers} />
<ReportsList reports={userData.allReports} />
<SystemSettings />
<AuditLogs />
</div>
);
break;
case 'superadmin':
panelContent = (
<div className="superadmin-panel">
<h2>Super Admin Dashboard</h2>
<OrganizationManagement />
<BillingOverview />
<SystemHealthMonitor />
<DatabaseBackups />
</div>
);
break;
default:
panelContent = (
<div className="no-access">
<h2>Access Denied</h2>
<p>Your account role is not recognized. Please contact support.</p>
</div>
);
}
return (
<div className="admin-container">
<Sidebar role={userRole} />
<main>{panelContent}</main>
</div>
);
}
Why this pattern: More readable than multiple if-else statements when you have 4+ distinct conditions based on a single value.
Production tip: Always include a default case for unexpected values. This prevents rendering nothing or breaking when data is malformed.
Quick summery - When to Use Each Conditional Rendering Pattern
| Pattern | Best For | Example Use Cases |
&& | Optional elements | Badges, tooltips, conditional features, notification indicators |
Ternary (? :) | Binary choices | Button text, icon toggles, class names, toggle states |
| Early Return | Multiple states | Data fetching, authentication checks, validation, loading/error states |
if statements | 2-4 conditions with else-if | Complex logic before return, multi-step authentication flows |
| Element Variables | Multiple related elements changing together | Keeping return statement clean, building complex conditional UIs |
switch | 4+ distinct cases from single value | Role-based rendering, status types, notification types, theme selection |
Using this your code will be clean and easy to debug. Use this as per requirement. Merge conditions to avoid complexity.






