React Rendering Empty States
Table of Contents + −
In the last lesson on React Rendering Loading States, you learned to show a spinner while data is on its way. This lesson handles the moment the data arrives empty, so the user sees a friendly message instead of a scary blank screen.
🤔 Why do empty states matter?
A blank screen is the scariest thing you can show a user. They can’t tell if it’s loading, broken, or just empty.
- An empty list with no message looks like a bug. The user thinks something failed.
- They have no idea what to do next. Is it loading? Did it crash? Should they wait?
- A short message clears all of that up. “No items yet, add one!” tells them everything in one line.
- Real apps do this everywhere. An empty cart says “Your cart is empty”. An empty inbox says “No new messages”.
So an empty state is just a friendly message you show when there’s no data to show. It turns confusing blank space into something that makes sense.
📭 What an empty state looks like
An empty state happens when your list has zero items in it. You check for that and show a message instead of the list.
- Your data is usually an array. A list of todos, a list of products, a list of messages.
- When that array is empty, its
lengthis0. That’s the signal you check for. - If
lengthis0, you show the message. Otherwise you show the list. - It’s the same conditional rendering you already know, just pointed at an empty list.
Here’s the check at the heart of it. We look at length to decide what to show.
const items = [];
if (items.length === 0) { // show "No items yet" message} else { // show the list}So items.length === 0 is the whole question. Is the list empty or not? Everything else is just deciding what to render for each case.
⚠️ Don’t reuse the && trick here
Remember the {items.length > 0 && ...} pattern from the && lesson? It’s great for showing the list. But on its own it does nothing for the empty case.
{items.length > 0 && <List />}shows the list only when there are items. Good so far.- But when the list is empty, that line renders nothing. The user is back to a blank screen.
&&only handles the “show it” side. It has no “otherwise show this” side.- For empty states you need both sides covered, so reach for a ternary or an early return instead.
Here’s the trap and the fix side by side.
// ❌ Wrong - empty list renders nothing, user sees a blank screenreturn <div>{items.length > 0 && <ItemList items={items} />}</div>;
// ✅ Right - a ternary covers BOTH casesreturn ( <div> {items.length === 0 ? <p>No items yet, add one!</p> : <ItemList items={items} />} </div>);So the && version quietly shows nothing when the list is empty. The ternary always shows something, which is exactly what you want.
🔀 The ternary way
A ternary is the most common way to pick between the empty message and the list. It’s one expression with two outcomes.
- The shape is
condition ? thingA : thingB. If the condition is true, you getthingA, elsethingB. - Put the empty check first:
items.length === 0. - If it’s true, render the message. If it’s false, render the list.
- This lives right inside your JSX in curly braces, so it reads almost like a sentence.
Here’s a small cart that shows a message when empty and the items otherwise. The ternary does the switching.
function Cart({ items }) { return ( <div> <h2>Your Cart</h2> {items.length === 0 ? ( <p>Your cart is empty. Start shopping!</p> ) : ( <ul> {items.map((item) => ( <li key={item.id}>{item.name}</li> ))} </ul> )} </div> );}So both cases are covered and the screen is never just blank:
- When
itemsis empty, you see the friendly line. - The moment something gets added, the list takes its place.
↩️ The early return way
When the empty state and the full list look very different, a ternary can get hard to read. An early return keeps each case clean and separate.
- You check for the empty case at the top of the component.
- If the list is empty, you
returnthe message right there and stop. - The rest of the function only runs when there’s actual data, so it stays simple.
- This is nice when the empty view has its own layout, like an image plus a button.
Here’s the same idea written with an early return. The empty case leaves the function before the list code ever runs.
function TodoList({ todos }) { if (todos.length === 0) { return <p>No tasks yet. Add your first one!</p>; }
return ( <ul> {todos.map((todo) => ( <li key={todo.id}>{todo.text}</li> ))} </ul> );}So you get two clean paths with no nesting:
- If there are no todos, React shows the message and never touches the
mapbelow. - Once a todo exists, that first
ifis skipped and the real list renders.
💬 Write a helpful empty message
A blank screen is bad, but a cold message like “No data” isn’t much better. A good empty message helps the user move forward.
- Say plainly what’s empty: “No tasks yet”, “Your cart is empty”, “No results found”.
- Add a small next step when it makes sense: “Add your first one!” or “Try a different search”.
- Keep the tone friendly and short. One line is usually enough.
- A button or link as a call to action turns a dead end into a starting point.
Here’s an empty state that does more than just announce the bad news. It invites the user to act.
function EmptyTodos({ onAdd }) { return ( <div> <p>No tasks yet. Ready to get started?</p> <button onClick={onAdd}>Add your first task</button> </div> );}So instead of leaving the user stuck, you hand them the next move. That’s the difference between an empty state that feels broken and one that feels helpful.
Match the message to the cause
An empty search result and an empty list are different. “No tasks yet” fits a brand-new list. “No results found” fits a search that matched nothing. Use the message that actually explains why it’s empty.
🧩 What You’ve Learned
- ✅ An empty state is a friendly message you show when a list has no items, instead of a blank screen
- ✅ A blank screen looks broken, so always cover the empty case
- ✅ Check for empty with
items.length === 0 - ✅
{items.length > 0 && <List />}shows nothing when empty, so it can’t handle the empty case alone - ✅ Use a ternary
condition ? message : listto cover both cases in one expression - ✅ Use an early return when the empty view has its own separate layout
- ✅ Write helpful messages that say what’s empty and offer a clear next step
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
Why should you render an empty state instead of just letting an empty list show nothing?
Why: When a list is empty and you show nothing, the user can't tell if it's loading, broken, or just empty. A short message clears that up and tells them what to do.
- 2
Which check tells you a list is empty?
Why: An array's length is 0 when it has no items, so items.length === 0 is the signal that the list is empty.
- 3
What goes wrong if you only use {items.length > 0 && <List />} for an empty list?
Why: The && pattern only handles the 'show it' side. When the list is empty the condition is false and nothing renders, so the empty case is left blank. Use a ternary or early return instead.
- 4
What makes an empty-state message helpful rather than confusing?
Why: A good empty message explains what's empty in plain words and gives the user a next step, often with a button as a call to action, so it's a starting point and not a dead end.
🚀 What’s Next?
You can now handle loading, errors, and empty data, so your screens always show something sensible. Next you’ll take a real array of data and turn it into a list of elements on the screen.