Conditional Rendering
What is Conditional Rendering?
Conditional rendering is showing different UI based on certain conditions. Just like if/else in JavaScript, you can control what gets displayed in your React components.
function Greeting({ isLoggedIn }) {
if (isLoggedIn) {
return <h1>Welcome back!</h1>;
}
return <h1>Please sign in.</h1>;
}
if/else Statements
Basic if/else
function LoginStatus({ isLoggedIn }) {
if (isLoggedIn) {
return <p>You are logged in</p>;
} else {
return <p>Please log in</p>;
}
}
With Variables
function Dashboard({ user }) {
let content;
if (user.isAdmin) {
content = <AdminPanel />;
} else {
content = <UserPanel />;
}
return (
<div>
<h1>Dashboard</h1>
{content}
</div>
);
}
Multiple Conditions
function StatusMessage({ status }) {
if (status === 'loading') {
return <p>Loading...</p>;
}
if (status === 'error') {
return <p style={{ color: 'red' }}>Error occurred!</p>;
}
if (status === 'success') {
return <p style={{ color: 'green' }}>Success!</p>;
}
return <p>Ready</p>;
}
Early Return Pattern
Return early to avoid nesting:
Loading State
function UserProfile({ user, isLoading }) {
if (isLoading) {
return <p>Loading user profile...</p>;
}
if (!user) {
return <p>User not found</p>;
}
// Main content
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}
Error Handling
function DataDisplay({ data, error }) {
if (error) {
return <div className="error">{error.message}</div>;
}
if (!data) {
return <div>No data available</div>;
}
return (
<div>
<h2>Data:</h2>
<pre>{JSON.stringify(data, null, 2)}</pre>
</div>
);
}
Ternary Operator (? :)
For simple if/else, use ternary operator inline:
Basic Ternary
function Message({ isOnline }) {
return (
<div>
<p>User is {isOnline ? 'online' : 'offline'}</p>
</div>
);
}
Rendering Components
function AuthButton({ isLoggedIn }) {
return (
<div>
{isLoggedIn ? (
<button>Log Out</button>
) : (
<button>Log In</button>
)}
</div>
);
}
With Different Components
function Content({ hasPermission }) {
return (
<div>
{hasPermission ? (
<SecretContent />
) : (
<AccessDenied />
)}
</div>
);
}
Nested Ternaries (Be Careful!)
function StatusBadge({ status }) {
return (
<span className={
status === 'active' ? 'badge-green' :
status === 'pending' ? 'badge-yellow' :
'badge-gray'
}>
{status}
</span>
);
}
// Better: use if/else or switch for multiple conditions
Logical && Operator
Show something only when condition is true:
Basic &&
function Notifications({ count }) {
return (
<div>
<h2>Notifications</h2>
{count > 0 && <p>You have {count} new notifications</p>}
</div>
);
}
Showing Components
function AdminPanel({ isAdmin }) {
return (
<div>
<h1>Dashboard</h1>
{isAdmin && <AdminControls />}
{isAdmin && <UserManagement />}
</div>
);
}
Multiple Conditions
function ProfileBadge({ user, isPremium, isVerified }) {
return (
<div>
<h2>{user.name}</h2>
{isPremium && <span className="badge">Premium</span>}
{isVerified && <span className="badge">Verified ✓</span>}
</div>
);
}
Watch Out for Falsy Values
// ❌ Bad - shows "0" when count is 0
function Items({ count }) {
return (
<div>
{count && <p>You have {count} items</p>}
</div>
);
}
// When count is 0, React renders "0"!
// ✅ Good - explicitly check
function Items({ count }) {
return (
<div>
{count > 0 && <p>You have {count} items</p>}
</div>
);
}
Logical || Operator
Show fallback when value is falsy:
function Welcome({ username }) {
return <h1>Hello, {username || 'Guest'}!</h1>;
}
function Avatar({ imageUrl }) {
return (
<img
src={imageUrl || '/default-avatar.png'}
alt="Profile"
/>
);
}
Note: Use nullish coalescing ?? to only fallback on null/undefined:
function Counter({ count }) {
// || would show fallback for 0
return <p>Count: {count ?? 'Not set'}</p>;
}
Switch Statements
For multiple mutually exclusive conditions:
function StatusIcon({ status }) {
let icon;
switch (status) {
case 'success':
icon = '✓';
break;
case 'error':
icon = '✗';
break;
case 'warning':
icon = '⚠';
break;
case 'info':
icon = 'ℹ';
break;
default:
icon = '○';
}
return <span className={`icon-${status}`}>{icon}</span>;
}
With Components
function PageContent({ page }) {
switch (page) {
case 'home':
return <HomePage />;
case 'about':
return <AboutPage />;
case 'contact':
return <ContactPage />;
case 'profile':
return <ProfilePage />;
default:
return <NotFoundPage />;
}
}
Object Mapping Pattern
Cleaner alternative to switch for component selection:
function PageContent({ page }) {
const pages = {
home: <HomePage />,
about: <AboutPage />,
contact: <ContactPage />,
profile: <ProfilePage />
};
return pages[page] || <NotFoundPage />;
}
With Functions
function Icon({ type }) {
const icons = {
success: () => <span>✓</span>,
error: () => <span>✗</span>,
warning: () => <span>⚠</span>,
info: () => <span>ℹ</span>
};
const IconComponent = icons[type] || icons.info;
return <IconComponent />;
}
Common Patterns
1. Loading State
function DataFetcher({ isLoading, data, error }) {
if (isLoading) {
return <div className="spinner">Loading...</div>;
}
if (error) {
return <div className="error">Error: {error.message}</div>;
}
return (
<div className="data">
{data.map(item => (
<div key={item.id}>{item.name}</div>
))}
</div>
);
}
2. Empty State
function TodoList({ todos }) {
if (todos.length === 0) {
return (
<div className="empty-state">
<p>No todos yet!</p>
<button>Add your first todo</button>
</div>
);
}
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
);
}
3. Permission-Based Rendering
function ActionButtons({ canEdit, canDelete }) {
return (
<div className="actions">
<button>View</button>
{canEdit && <button>Edit</button>}
{canDelete && <button>Delete</button>}
</div>
);
}
4. Feature Flags
function App({ features }) {
return (
<div>
<Header />
{features.showBanner && <PromoBanner />}
<MainContent />
{features.showChat && <ChatWidget />}
{features.newDesign ? <NewFooter /> : <OldFooter />}
</div>
);
}
5. Authentication
function App({ user }) {
if (!user) {
return <LoginPage />;
}
return (
<div>
<Header user={user} />
<Dashboard />
{user.isAdmin && <AdminPanel />}
</div>
);
}
6. Conditional CSS Classes
function Button({ isPrimary, isDisabled, children }) {
const className = [
'btn',
isPrimary && 'btn-primary',
isDisabled && 'btn-disabled'
].filter(Boolean).join(' ');
return <button className={className}>{children}</button>;
}
// Or with template literals
function Button({ isPrimary, isDisabled, children }) {
return (
<button className={`
btn
${isPrimary ? 'btn-primary' : ''}
${isDisabled ? 'btn-disabled' : ''}
`.trim()}>
{children}
</button>
);
}
Conditional Rendering with Arrays
Filter and Map
function ProductList({ products, showOnSale }) {
return (
<div>
{products
.filter(product => !showOnSale || product.onSale)
.map(product => (
<ProductCard key={product.id} product={product} />
))}
</div>
);
}
Multiple Conditions
function UserList({ users, showActive, showPremium }) {
return (
<div>
{users
.filter(user => {
if (showActive && !user.isActive) return false;
if (showPremium && !user.isPremium) return false;
return true;
})
.map(user => (
<UserCard key={user.id} user={user} />
))}
</div>
);
}
Best Practices
✅ DO:
// Use early returns for error/loading states
function Component({ data, isLoading, error }) {
if (isLoading) return <Spinner />;
if (error) return <Error />;
return <Content data={data} />;
}
// Use ternary for simple if/else
<div>{isLoggedIn ? <LogoutButton /> : <LoginButton />}</div>
// Use && for showing content when true
{hasNotifications && <NotificationBadge />}
// Explicitly check numbers
{count > 0 && <p>Count: {count}</p>}
// Use switch/object mapping for multiple cases
const views = {
home: <Home />,
profile: <Profile />
};
❌ DON’T:
// Don't use && with numbers that could be 0
{count && <p>{count} items</p>} // Shows "0" when count is 0!
// Don't nest ternaries too deeply
{a ? (b ? c : d) : (e ? f : g)} // Hard to read!
// Don't forget null can be rendered
{user.name && <p>{user.name}</p>} // What if name is null?
// Don't use if/else for simple inline cases
let button;
if (isLoggedIn) {
button = <LogoutButton />;
} else {
button = <LoginButton />;
}
return <div>{button}</div>;
// Better: {isLoggedIn ? <LogoutButton /> : <LoginButton />}
Choosing the Right Method
| Method | Use Case | Example |
|---|---|---|
if/else |
Multiple statements, complex logic | Loading/error handling |
| Early return | Guard clauses, error handling | Validation, permissions |
Ternary ? : |
Simple if/else inline | {isOn ? 'On' : 'Off'} |
Logical && |
Show when true | {isAdmin && <Panel />} |
| Switch | Multiple exclusive options | Page routing, status icons |
| Object map | Dynamic component selection | Feature flags, themes |
Quick Guide:
- 2 options → Ternary or if/else
- Show/hide one thing → &&
- 3+ options → Switch or object map
- Complex logic → if/else with early returns
Summary
Basic Syntax:
// if/else
if (condition) {
return <ComponentA />;
} else {
return <ComponentB />;
}
// Ternary
{condition ? <ComponentA /> : <ComponentB />}
// Logical &&
{condition && <Component />}
// Early return
if (!data) return <Loading />;
return <Content />;
Common Patterns:
- Loading states: Early return with if
- Show/hide: Logical &&
- A or B: Ternary operator
- Multiple cases: Switch or object map
Remember:
0and""render in React (avoid{count && ...})null,undefined,true,falsedon’t render- Use
>= 0,!== ''for explicit checks
Next Article: Lists and Keys