React applications often need to display different content depending on what is happening in the application.
For example:
- Show a login button when a user is logged out.
- Show a dashboard when the user is logged in.
- Display a loading message while data is being fetched.
- Display an error message when something goes wrong.
- Show a success message after a form is submitted.
- Display different components based on a user’s role.
- Show or hide an element based on a condition.
This is called conditional rendering.
Conditional rendering means rendering different JSX depending on whether a condition is true or false.
React uses normal JavaScript techniques for conditional rendering. You can use if statements, ternary operators, logical &&, early returns, and other JavaScript expressions to decide what should appear on the screen.
For example:
function App() {
const isLoggedIn = true;
if (isLoggedIn) {
return <h1>Welcome back!</h1>;
}
return <h1>Please log in.</h1>;
}
export default App;
When isLoggedIn is true, React displays:
Welcome back!
When it is false, React displays:
Please log in.
Understanding conditional rendering is essential because almost every real-world React application needs to change its UI based on data, state, user actions, or application status.
What Is Conditional Rendering?
Conditional rendering is the process of displaying different UI depending on a condition.
The basic idea is:
Condition
↓
Is it true?
↓
Yes → Render one UI
No → Render another UI
For example:
function App() {
const isLoggedIn = false;
return (
<div>
{isLoggedIn ? (
<h1>Welcome!</h1>
) : (
<h1>Please log in.</h1>
)}
</div>
);
}
export default App;
Because isLoggedIn is false, React renders:
Please log in.
If the value changes to true, React renders:
Welcome!
Why Is Conditional Rendering Important?
A modern application rarely displays exactly the same interface all the time.
Consider an online shopping website.
When a user visits the website, the application might show:
Loading products...
After the products load:
Laptop
Keyboard
Mouse
If the request fails:
Unable to load products.
If there are no products:
No products found.
The UI changes based on the application’s current state.
Conditional rendering allows React to represent these different states clearly.
Common situations include:
- Authentication
- Loading states
- Error states
- Empty states
- Permissions
- User roles
- Form validation
- Navigation
- Search results
- Shopping carts
- Notifications
- Feature availability
How Conditional Rendering Works in React
React does not have a special if rendering syntax.
Instead, React uses JavaScript conditions to determine which JSX should be returned.
For example:
function Greeting() {
const isLoggedIn = true;
if (isLoggedIn) {
return <h2>Welcome back!</h2>;
}
return <h2>Please log in.</h2>;
}
The JavaScript condition determines which JSX React receives.
You can think of it as:
JavaScript condition
↓
Choose JSX
↓
React renders JSX
There are several common approaches.
Using if Statements
An if statement is one of the easiest ways to understand conditional rendering.
function Greeting() {
const isLoggedIn = true;
if (isLoggedIn) {
return <h1>Welcome back!</h1>;
}
return <h1>Please log in.</h1>;
}
export default Greeting;
Here, React checks:
if (isLoggedIn)
If the condition is true, the first return executes.
If the condition is false, the second return executes.
Understanding the Example
Suppose:
const isLoggedIn = true;
The condition becomes:
if (true)
Therefore:
<h1>Welcome back!</h1>
is rendered.
If:
const isLoggedIn = false;
the condition becomes:
if (false)
and React renders:
<h1>Please log in.</h1>
Using if...else
You can also write:
function App() {
const isAdmin = true;
if (isAdmin) {
return <h1>Admin Dashboard</h1>;
} else {
return <h1>User Dashboard</h1>;
}
}
export default App;
The else block runs when the condition is false.
When Should You Use if?
if statements are particularly useful when:
- The logic is complex.
- You have several conditions.
- You need to perform calculations before rendering.
- You want an early return.
- Different conditions produce substantially different UI.
For simple inline conditions, a ternary operator or && can often be shorter.
The Ternary Operator
The ternary operator is one of the most common ways to conditionally render JSX.
Its basic syntax is:
condition ? valueIfTrue : valueIfFalse
For example:
function App() {
const isLoggedIn = true;
return (
<div>
{isLoggedIn ? (
<h1>Welcome!</h1>
) : (
<h1>Please log in.</h1>
)}
</div>
);
}
export default App;
The condition is:
isLoggedIn
If it is true:
<h1>Welcome!</h1>
is rendered.
If it is false:
<h1>Please log in.</h1>
is rendered.
Simple Ternary Example
A ternary can also be used for small pieces of text.
function App() {
const isOnline = true;
return (
<p>
Status: {isOnline ? "Online" : "Offline"}
</p>
);
}
export default App;
Ternary with Buttons
function App() {
const isLoggedIn = false;
return (
<div>
{isLoggedIn ? (
<button>Logout</button>
) : (
<button>Login</button>
)}
</div>
);
}
export default App;
Ternary with Components
You can conditionally render entire components.
function App() {
const isLoggedIn = true;
return (
<div>
{isLoggedIn ? <Dashboard /> : <Login />}
</div>
);
}
This is useful when two different components represent two different application states.
Logical && Rendering
The logical AND operator, &&, is useful when you want to render something only when a condition is true.
Example:
function App() {
const isLoggedIn = true;
return (
<div>
{isLoggedIn && <p>Welcome back!</p>}
</div>
);
}
export default App;
If isLoggedIn is true, React renders:
Welcome back!
If it is false, React renders nothing for that expression.
Understanding the Logic
JavaScript evaluates:
true && "Hello"
as:
Hello
But:
false && "Hello"
results in:
false
React does not render the boolean false as visible text.
Therefore:
{isLoggedIn && <Dashboard />}
means:
Render
<Dashboard />only ifisLoggedInis truthy.
Showing Notifications
function App() {
const hasNotification = true;
return (
<div>
<h1>Dashboard</h1>
{hasNotification && (
<p>You have new notifications.</p>
)}
</div>
);
}
export default App;
Showing an Element Based on State
import { useState } from "react";
function App() {
const [showMessage, setShowMessage] = useState(false);
return (
<div>
<button onClick={() => setShowMessage(!showMessage)}>
Toggle Message
</button>
{showMessage && (
<p>This message is visible.</p>
)}
</div>
);
}
export default App;
When the button is clicked, the state changes and React updates the UI.
An Important && Gotcha
Be careful when the value on the left side can be 0.
For example:
function App() {
const messageCount = 0;
return (
<div>
{messageCount && <p>You have messages.</p>}
</div>
);
}
The expression evaluates to:
0
Unlike false, null, or undefined, React can render the number 0.
You may therefore see 0 on the screen.
A safer approach is:
{messageCount > 0 && (
<p>You have messages.</p>
)}
Now the condition explicitly checks whether there are messages.
This is an important detail to remember when using && with numbers.
Multiple Conditions
Real applications often have more than two possible states.
For example, a user might be:
- An administrator
- A regular user
- A guest
You can use multiple conditions to render the appropriate UI.
Using if Statements
function Dashboard({ role }) {
if (role === "admin") {
return <h1>Admin Dashboard</h1>;
}
if (role === "user") {
return <h1>User Dashboard</h1>;
}
return <h1>Guest Area</h1>;
}
export default Dashboard;
This is usually easier to read than deeply nested ternary expressions.
Multiple Ternary Conditions
You can technically write:
function App({ role }) {
return (
<div>
{role === "admin" ? (
<AdminPanel />
) : role === "user" ? (
<UserPanel />
) : (
<GuestPanel />
)}
</div>
);
}
This works, but deeply nested ternaries can become difficult to read.
For more complex logic, an if statement or another approach may be clearer.
Using Logical Operators for Multiple Conditions
You can combine conditions with JavaScript operators.
For example:
function App({ isLoggedIn, isAdmin }) {
return (
<div>
{isLoggedIn && isAdmin && (
<button>Admin Settings</button>
)}
</div>
);
}
The button appears only when both conditions are true.
This is equivalent to:
Logged in?
↓
Yes
↓
Administrator?
↓
Yes
↓
Show Admin Settings
Conditional Components
Sometimes the condition determines which entire component should appear.
For example:
function App({ isLoggedIn }) {
if (isLoggedIn) {
return <Dashboard />;
}
return <Login />;
}
Here, React renders one of two components.
You can also use a ternary:
function App({ isLoggedIn }) {
return (
<div>
{isLoggedIn ? <Dashboard /> : <Login />}
</div>
);
}
Conditional Navigation
A navigation bar may also depend on authentication.
function Navigation({ isLoggedIn }) {
return (
<nav>
<a href="/">Home</a>
{isLoggedIn ? (
<>
<a href="/profile">Profile</a>
<button>Logout</button>
</>
) : (
<a href="/login">Login</a>
)}
</nav>
);
}
The navigation changes according to the user’s state.
Conditional Components Based on Role
function App({ role }) {
if (role === "admin") {
return <AdminDashboard />;
}
if (role === "editor") {
return <EditorDashboard />;
}
return <UserDashboard />;
}
This approach is useful for applications where different users have different capabilities.
Early Return
An early return means returning from a component before reaching the main JSX.
This is particularly useful for loading, error, authentication, and permission states.
For example:
function Profile({ user }) {
if (!user) {
return <p>Please log in.</p>;
}
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}
Instead of putting the entire main UI inside another condition, we handle the special case first.
Why Early Returns Are Useful
Compare this:
function Profile({ user }) {
return (
<div>
{user ? (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
) : (
<p>Please log in.</p>
)}
</div>
);
}
with:
function Profile({ user }) {
if (!user) {
return <p>Please log in.</p>;
}
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}
The second version can be easier to read when the component has a larger UI.
Loading UI
Applications often need to retrieve information from an API or another data source.
While the request is running, the application should tell the user that the information is loading.
A common pattern is:
function Products({ loading, products }) {
if (loading) {
return <p>Loading products...</p>;
}
return (
<div>
{products.map((product) => (
<p key={product.id}>
{product.name}
</p>
))}
</div>
);
}
The component first checks:
if (loading)
If loading is true, it returns the loading UI.
Once loading becomes false, React renders the products.
Loading with State
A simplified example using state:
import { useEffect, useState } from "react";
function Products() {
const [products, setProducts] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
setTimeout(() => {
setProducts([
{ id: 1, name: "Laptop" },
{ id: 2, name: "Keyboard" }
]);
setLoading(false);
}, 2000);
}, []);
if (loading) {
return <h2>Loading products...</h2>;
}
return (
<div>
<h1>Products</h1>
{products.map((product) => (
<p key={product.id}>
{product.name}
</p>
))}
</div>
);
}
export default Products;
This example simulates a two-second loading period.
In a real application, loading state would normally be controlled by the result of an asynchronous operation.
Error UI
Not every request succeeds.
A network request can fail because:
- The server is unavailable.
- The internet connection is interrupted.
- The API returns an error.
- The requested resource does not exist.
- The application encounters an unexpected problem.
A React application should provide useful feedback instead of leaving the user wondering what happened.
For example:
function Products({ loading, error, products }) {
if (loading) {
return <p>Loading products...</p>;
}
if (error) {
return <p>Unable to load products.</p>;
}
return (
<div>
{products.map((product) => (
<p key={product.id}>
{product.name}
</p>
))}
</div>
);
}
The component now has three states:
Loading
↓
Error or Success
↓
Display appropriate UI
Loading, Error, and Success
A more complete example:
function Products({ loading, error, products }) {
if (loading) {
return <p>Loading products...</p>;
}
if (error) {
return (
<div>
<h2>Something went wrong</h2>
<p>We couldn't load the products.</p>
</div>
);
}
if (products.length === 0) {
return <p>No products found.</p>;
}
return (
<div>
{products.map((product) => (
<article key={product.id}>
<h2>{product.name}</h2>
</article>
))}
</div>
);
}
This example handles four possible UI states:
- Loading
- Error
- Empty
- Success
This is a common pattern in real React applications.
Handling Empty States
An empty state is another form of conditional rendering.
For example:
function ProductList({ products }) {
if (products.length === 0) {
return <p>No products are available.</p>;
}
return (
<div>
{products.map((product) => (
<p key={product.id}>
{product.name}
</p>
))}
</div>
);
}
Empty states are important because an empty array is not necessarily an error.
For example:
Loading → The application is still retrieving data.
Error → Something went wrong.
Empty → The request succeeded, but there is no data.
Success → Data is available.
These states should usually have different UI.
Conditional Rendering with State
State is frequently used as the condition.
For example:
import { useState } from "react";
function App() {
const [isVisible, setIsVisible] = useState(false);
return (
<div>
<button onClick={() => setIsVisible(!isVisible)}>
Toggle
</button>
{isVisible && (
<p>
This content is visible.
</p>
)}
</div>
);
}
export default App;
The state controls whether the paragraph appears.
When:
isVisible === true
the paragraph is rendered.
When:
isVisible === false
it is not rendered.
Conditional Rendering with Props
Conditions can also come from props.
function Welcome({ isLoggedIn }) {
return (
<div>
{isLoggedIn ? (
<h1>Welcome back!</h1>
) : (
<h1>Please log in.</h1>
)}
</div>
);
}
A parent component can control the child’s UI by passing different prop values.
function App() {
return (
<Welcome isLoggedIn={true} />
);
}
This connects conditional rendering with React’s component and props system.
Combining Conditions
You can combine JavaScript conditions using operators such as:
&&||!===!==><>=<=
For example:
function Account({ isLoggedIn, isPremium }) {
return (
<div>
{!isLoggedIn && (
<p>Please log in.</p>
)}
{isLoggedIn && isPremium && (
<p>Premium content unlocked.</p>
)}
</div>
);
}
Here:
!isLoggedIn
means the user is not logged in.
And:
isLoggedIn && isPremium
means both conditions must be true.
Choosing the Right Conditional Rendering Technique
Different situations call for different approaches.
| Technique | Best for |
|---|---|
if | Complex conditions |
if...else | Two larger alternatives |
Ternary ? : | Choosing between two values or UIs |
&& | Showing something only when true |
| Early return | Loading, errors, authentication, permissions |
Multiple if statements | Several mutually exclusive states |
| Conditional component | Switching between different components |
For example, this is simple and readable:
{isLoggedIn && <Dashboard />}
This is useful when there is only one thing to conditionally show.
For two alternatives:
{isLoggedIn ? <Dashboard /> : <Login />}
For several application states:
if (loading) {
return <Loading />;
}
if (error) {
return <Error />;
}
if (products.length === 0) {
return <EmptyState />;
}
return <ProductList products={products} />;
Avoiding Deeply Nested Ternaries
Although nested ternaries are valid JavaScript, they can become difficult to understand.
For example:
return (
<div>
{loading ? (
<Loading />
) : error ? (
<Error />
) : products.length === 0 ? (
<Empty />
) : (
<ProductList />
)}
</div>
);
This works, but as conditions grow, readability suffers.
An early-return approach is often clearer:
if (loading) {
return <Loading />;
}
if (error) {
return <Error />;
}
if (products.length === 0) {
return <Empty />;
}
return <ProductList />;
The important principle is not to avoid ternaries completely. Use them when they make the code clearer.
Conditional Rendering and User Authentication
Authentication is one of the most common real-world examples.
function App({ user }) {
if (!user) {
return <Login />;
}
return <Dashboard user={user} />;
}
The UI changes depending on whether the user exists.
You can also handle different permissions:
function Dashboard({ user }) {
if (user.role === "admin") {
return <AdminDashboard />;
}
if (user.role === "editor") {
return <EditorDashboard />;
}
return <UserDashboard />;
}
The same principle can be used for:
- Admin panels
- Content management systems
- SaaS applications
- E-commerce websites
- Learning platforms
- Social media applications
Conditional Rendering and Forms
Conditional rendering is commonly used in forms.
For example:
import { useState } from "react";
function SignupForm() {
const [submitted, setSubmitted] = useState(false);
function handleSubmit(event) {
event.preventDefault();
setSubmitted(true);
}
if (submitted) {
return <h2>Account created successfully!</h2>;
}
return (
<form onSubmit={handleSubmit}>
<input placeholder="Name" />
<input placeholder="Email" />
<button type="submit">
Create Account
</button>
</form>
);
}
export default SignupForm;
Before submission, the form is shown.
After submission, the success message is shown.
Conditional Rendering and Search Results
Search interfaces frequently have several states.
function SearchResults({ loading, results, error }) {
if (loading) {
return <p>Searching...</p>;
}
if (error) {
return <p>Search failed.</p>;
}
if (results.length === 0) {
return <p>No results found.</p>;
}
return (
<div>
{results.map((result) => (
<article key={result.id}>
<h2>{result.title}</h2>
</article>
))}
</div>
);
}
This gives users useful feedback regardless of the current application state.
Real-World Web4Learners Example
Imagine Web4Learners has a React tutorial search page.
The page might have these states:
Before Searching
Search React tutorials
While Searching
Searching for React...
Results Found
React Props
React State
React Events
React Hooks
No Results
No tutorials found.
Error
Unable to load tutorials. Please try again.
A component could represent these states using conditional rendering:
function TutorialResults({
loading,
error,
tutorials
}) {
if (loading) {
return (
<p>
Searching for tutorials...
</p>
);
}
if (error) {
return (
<div>
<h2>Unable to load tutorials</h2>
<button>Try Again</button>
</div>
);
}
if (tutorials.length === 0) {
return (
<p>
No tutorials found.
</p>
);
}
return (
<div>
{tutorials.map((tutorial) => (
<article key={tutorial.id}>
<h2>{tutorial.title}</h2>
<p>{tutorial.description}</p>
</article>
))}
</div>
);
}
export default TutorialResults;
This is a realistic example of how conditional rendering controls the interface of a content-based website.
Image Placement: Conditional Rendering Flow
Place this image immediately after the “How Conditional Rendering Works in React” section.
Create a modern 16:9 educational infographic showing:
Condition → True / False → Different UI
Use three examples:
- Logged in → Dashboard
- Logged out → Login
- Loading → Loading UI
Use a modern Web4Learners design style with clean typography, rounded cards, subtle gradients, React-inspired developer visuals, and minimal text. Make the flow immediately understandable to a beginner.
Image Placement: React UI States
Place this image immediately before the “Loading UI” section.
Create a modern 16:9 infographic showing four common React UI states:
Loading → Success → Empty → Error
Represent each state with a simple modern interface card.
Use a clean developer-focused design with contemporary typography, rounded corners, subtle gradients, and minimal text. Avoid making the image look like an old-fashioned flowchart.
Common Conditional Rendering Mistakes
Using = Instead of ===
Incorrect:
if (isLoggedIn = true) {
return <Dashboard />;
}
This assigns a value instead of checking it.
Usually you should simply write:
if (isLoggedIn) {
return <Dashboard />;
}
Or when comparing values:
if (role === "admin") {
return <AdminDashboard />;
}
Using && with a Number Without Checking It
Potentially problematic:
{count && <p>There are items.</p>}
If count is 0, React can render 0.
Prefer:
{count > 0 && (
<p>There are items.</p>
)}
Making Ternaries Too Complicated
Avoid turning a simple condition into a large nested expression.
Instead of:
condition1
? ...
: condition2
? ...
: condition3
? ...
: ...
consider early returns or separate components.
Forgetting the Empty State
An application should not assume that data always exists.
For example:
if (products.length === 0) {
return <p>No products found.</p>;
}
An empty result can be a valid application state.
Treating Errors as Loading
Loading and error states are different.
Avoid showing:
Loading...
forever when a request has actually failed.
Represent the states separately:
if (loading) {
return <Loading />;
}
if (error) {
return <Error />;
}
Best Practices for Conditional Rendering
Keep Conditions Easy to Understand
Simple conditions are easier to maintain.
Instead of repeating complicated logic:
{user && user.account && user.account.subscription && ...}
consider calculating a meaningful value first when appropriate.
const hasPremiumAccess =
user?.account?.subscription === "premium";
Then:
{hasPremiumAccess && <PremiumContent />}
Use Early Returns for Major States
Early returns are particularly useful for:
- Loading
- Error
- Authentication
- Authorization
- Empty data
Example:
if (loading) {
return <Loading />;
}
if (error) {
return <Error />;
}
Use Ternaries for Simple Alternatives
Good:
{isLoggedIn ? <Dashboard /> : <Login />}
This clearly expresses two alternatives.
Use && for Optional Content
Good:
{isAdmin && <AdminTools />}
The intent is immediately understandable.
Create Separate Components When UI Gets Large
If a conditional block becomes large, move it into its own component.
Instead of keeping a huge conditional inside one component:
{isAdmin ? (
// lots of JSX
) : (
// lots more JSX
)}
consider:
{isAdmin ? <AdminPanel /> : <UserPanel />}
This keeps the parent component easier to understand.
Conditional Rendering Cheat Sheet
| Situation | Recommended approach |
|---|---|
| One condition | && |
| Two alternatives | Ternary |
| Complex logic | if |
| Loading state | Early return |
| Error state | Early return |
| Empty state | Early return or conditional rendering |
| Different user roles | if or conditional components |
| Show/hide UI | && |
| Switch between components | Ternary or if |
| Multiple mutually exclusive states | Multiple if statements |
Basic if
if (isLoggedIn) {
return <Dashboard />;
}
return <Login />;
Ternary
{isLoggedIn ? <Dashboard /> : <Login />}
Logical &&
{isAdmin && <AdminTools />}
Early Return
if (loading) {
return <Loading />;
}
Multiple States
if (loading) {
return <Loading />;
}
if (error) {
return <Error />;
}
if (items.length === 0) {
return <Empty />;
}
return <List items={items} />;
Practice Exercise
Build a React Product Dashboard that handles different UI states.
Your application should have:
- A loading state
- An error state
- An empty state
- A successful product list
- An admin-only button
- A login/logout state
Try to use:
if
? :
&&
and early returns.
Expected Behavior
When data is loading:
Loading products...
When an error occurs:
Unable to load products.
When there are no products:
No products found.
When products are available:
Laptop
Keyboard
Mouse
If the user is an administrator, also show:
Manage Products
If the user is not logged in, show:
Please log in.
Try to organize the conditions so that the component remains easy to read.
Key Takeaways
Conditional rendering allows React applications to display different UI based on application state, props, data, and user actions.
The most important concepts to remember are:
- Conditional rendering means showing different UI depending on a condition.
- React uses normal JavaScript conditions for conditional rendering.
ifstatements are useful for complex conditions.- The ternary operator is useful when choosing between two alternatives.
- Logical
&&is useful when something should appear only when a condition is true. - Be careful when using
&&with numbers such as0. - Multiple
ifstatements can handle several mutually exclusive states. - Early returns make loading, error, authentication, and empty states easier to manage.
- Conditional components can switch between completely different UI sections.
- Loading, error, empty, and success states should usually be handled separately.
- Conditions can be based on state, props, API data, authentication, permissions, and user actions.
- Avoid deeply nested ternary expressions when they make the code difficult to read.
- Move large conditional UI sections into separate components when appropriate.
- Good conditional rendering makes an application’s interface predictable and easier for users to understand.
A useful way to think about conditional rendering is:
Application State
↓
Condition
↓
Choose UI
↓
React Renders It
Once you understand this pattern, you can build interfaces that respond naturally to changing data and user actions. Conditional rendering is one of the core techniques that turns static React components into dynamic application interfaces.