An empty state is what a screen shows when there is nothing to list yet: a new account, a search with no matches, a cleared inbox or a failed load. Each needs a plain explanation and a way forward. The ten designs below cover every common case with editable HTML and CSS, plus a builder that writes accessible markup.
| Kind | Why it is empty | Primary action |
|---|---|---|
| First use | Nothing has been created yet | Create the first item, or import |
| No results | A search or filter matched nothing | Clear filters or change the search |
| All done | The user finished everything | None needed; confirm the good news |
| Error | Data failed to load | Try again, with a short reason |
| No access | The user lacks permission | Request access or switch account |
Updated
Empty screens are the first thing new users meet and the place people land after a search goes wrong, yet they are often a grey box saying No data. These examples treat each kind of empty differently, because the right message after a typo is not the right message on day one. Every snippet is self-contained and uses plain shapes rather than stock illustrations.
Write the heading, sentence and button, pick the kind, and copy accessible HTML and CSS. Starting output:
<div class="empty" role="status">
<div class="empty-art" aria-hidden="true"></div>
<h2>No invoices yet</h2>
<p>Invoices you send will appear here, with their status and due date.</p>
<button type="button">Create an invoice</button>
</div>.empty { max-width: 360px; margin: 0 auto; padding: 32px 20px; text-align: center; }
.empty-art { width: 56px; height: 56px; margin: 0 auto 12px; border-radius: 14px; border: 2px dashed #2563eb; }
.empty h2 { margin: 0 0 6px; font-size: 18px; }
.empty p { margin: 0 0 16px; color: #4b5563; }
.empty button { padding: 9px 16px; border: 0; border-radius: 8px; background: #2563eb; color: #fff; font-weight: 600; }A dashed outline hints at where the item will appear. The button is inside the empty area so nobody hunts for it.
<style>
.es { max-width: 380px; margin: 0 auto; text-align: center; font-family: system-ui, sans-serif; color: #111827 }
.es h2 { margin: 0 0 6px; font-size: 18px } .es p { margin: 0 0 14px; color: #4b5563 }
.es .btn { padding: 9px 16px; border: 0; border-radius: 8px; font-weight: 600 }
.box { padding: 28px 16px; border: 2px dashed #93c5fd; border-radius: 14px }
.btn { background: #2563eb; color: #fff }
</style>
<div class="es box"><h2>No projects yet</h2><p>Projects hold your pages, images and settings.</p><button class="btn">New project</button></div>Offering create or import respects people who already have data elsewhere.
<style>
.es { max-width: 380px; margin: 0 auto; text-align: center; font-family: system-ui, sans-serif; color: #111827 }
.es h2 { margin: 0 0 6px; font-size: 18px } .es p { margin: 0 0 14px; color: #4b5563 }
.es .btn { padding: 9px 16px; border: 0; border-radius: 8px; font-weight: 600 }
.row { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap }
.a { background: #111827; color: #fff } .b { background: #fff; color: #111827; border: 1px solid #d1d5db }
</style>
<div class="es"><h2>Your contact list is empty</h2><p>Add people one at a time or bring in a CSV from another tool.</p><div class="row"><button class="btn a">Add contact</button><button class="btn b">Import CSV</button></div></div>A short list with the first step marked turns an empty dashboard into a plan.
<style>
.es { max-width: 380px; margin: 0 auto; text-align: center; font-family: system-ui, sans-serif; color: #111827 }
.es h2 { margin: 0 0 6px; font-size: 18px } .es p { margin: 0 0 14px; color: #4b5563 }
.es .btn { padding: 9px 16px; border: 0; border-radius: 8px; font-weight: 600 }
ol { text-align: left; margin: 0 auto 14px; padding-left: 20px; max-width: 260px }
li.done { color: #9ca3af; text-decoration: line-through }
</style>
<div class="es"><h2>Let's get your shop ready</h2><ol><li class="done">Create account</li><li><strong>Add your first product</strong></li><li>Connect payments</li></ol><button class="btn" style="background:#059669;color:#fff">Add product</button></div>A clearly marked example row shows what the screen will look like once it is full.
<style>
.es { max-width: 380px; margin: 0 auto; text-align: center; font-family: system-ui, sans-serif; color: #111827 }
.es h2 { margin: 0 0 6px; font-size: 18px } .es p { margin: 0 0 14px; color: #4b5563 }
.es .btn { padding: 9px 16px; border: 0; border-radius: 8px; font-weight: 600 }
table { width: 100%; border-collapse: collapse; font-size: 14px; margin-bottom: 12px }
td { padding: 8px; border: 1px dashed #cbd5e1; color: #64748b }
.tag { font-size: 11px; padding: 2px 6px; border-radius: 6px; background: #fef3c7; color: #92400e }
</style>
<div class="es"><table><tr><td>Example: Website redesign</td><td>Due 30 Oct</td><td><span class="tag">Sample</span></td></tr></table><p>Tasks you add will replace this example.</p><button class="btn" style="background:#4f46e5;color:#fff">Add a task</button></div>Repeat the term, suggest fixes, and keep a way back to everything.
<style>
.es { max-width: 380px; margin: 0 auto; text-align: center; font-family: system-ui, sans-serif; color: #111827 }
.es h2 { margin: 0 0 6px; font-size: 18px } .es p { margin: 0 0 14px; color: #4b5563 }
.es .btn { padding: 9px 16px; border: 0; border-radius: 8px; font-weight: 600 }
q { font-weight: 600 } ul { text-align: left; max-width: 240px; margin: 0 auto 12px; color: #4b5563 }
</style>
<div class="es"><h2>No matches for <q>blue tshirt</q></h2><ul><li>Check the spelling</li><li>Try a shorter word, such as shirt</li></ul><a href="#">Browse all clothing</a></div>Showing the active filters as removable chips points straight at the cause.
<style>
.es { max-width: 380px; margin: 0 auto; text-align: center; font-family: system-ui, sans-serif; color: #111827 }
.es h2 { margin: 0 0 6px; font-size: 18px } .es p { margin: 0 0 14px; color: #4b5563 }
.es .btn { padding: 9px 16px; border: 0; border-radius: 8px; font-weight: 600 }
.chips { display: flex; gap: 6px; justify-content: center; flex-wrap: wrap; margin-bottom: 12px }
.chips span { padding: 4px 10px; border-radius: 999px; background: #e0e7ff; font-size: 13px }
.btn { background: #fff; border: 1px solid #6366f1; color: #4338ca }
</style>
<div class="es" role="status"><h2>No orders match these filters</h2><div class="chips"><span>Status: Refunded</span><span>Last 7 days</span></div><button class="btn">Clear filters</button></div>Some empty screens are good news. A calm confirmation is enough; no button needed.
<style>
.es { max-width: 380px; margin: 0 auto; text-align: center; font-family: system-ui, sans-serif; color: #111827 }
.es h2 { margin: 0 0 6px; font-size: 18px } .es p { margin: 0 0 14px; color: #4b5563 }
.es .btn { padding: 9px 16px; border: 0; border-radius: 8px; font-weight: 600 }
.tick { width: 48px; height: 48px; margin: 0 auto 10px; border-radius: 50%; background: #dcfce7; color: #15803d; font-size: 26px; line-height: 48px }
</style>
<div class="es"><div class="tick" aria-hidden="true">✓</div><h2>You're all caught up</h2><p>New messages will show up here.</p></div>Name the problem honestly, say the data is safe if it is, and offer a retry.
<style>
.es { max-width: 380px; margin: 0 auto; text-align: center; font-family: system-ui, sans-serif; color: #111827 }
.es h2 { margin: 0 0 6px; font-size: 18px } .es p { margin: 0 0 14px; color: #4b5563 }
.es .btn { padding: 9px 16px; border: 0; border-radius: 8px; font-weight: 600 }
.box { padding: 20px; border-radius: 12px; background: #fef2f2 }
.btn { background: #b91c1c; color: #fff }
</style>
<div class="es box"><h2>We couldn't load your invoices</h2><p>Your data is safe. Check your connection and try again.</p><button class="btn">Try again</button></div>Tell people who to ask, and give them a button that does the asking.
<style>
.es { max-width: 380px; margin: 0 auto; text-align: center; font-family: system-ui, sans-serif; color: #111827 }
.es h2 { margin: 0 0 6px; font-size: 18px } .es p { margin: 0 0 14px; color: #4b5563 }
.es .btn { padding: 9px 16px; border: 0; border-radius: 8px; font-weight: 600 }
.lock { width: 40px; height: 34px; margin: 0 auto 12px; border: 3px solid #64748b; border-radius: 6px; position: relative }
.lock::before { content: ""; position: absolute; left: 7px; top: -18px; width: 20px; height: 16px; border: 3px solid #64748b; border-bottom: 0; border-radius: 12px 12px 0 0 }
.btn { background: #334155; color: #fff }
</style>
<div class="es"><div class="lock" aria-hidden="true"></div><h2>You need access to this report</h2><p>Reports are shared by workspace admins. Your admin is Dana Price.</p><button class="btn">Request access</button></div>Keeping the column headers shows what will appear, and a single row spans them with the message.
<style>
.es { max-width: 380px; margin: 0 auto; text-align: center; font-family: system-ui, sans-serif; color: #111827 }
.es h2 { margin: 0 0 6px; font-size: 18px } .es p { margin: 0 0 14px; color: #4b5563 }
.es .btn { padding: 9px 16px; border: 0; border-radius: 8px; font-weight: 600 }
table { width: 100%; border-collapse: collapse; font-size: 14px }
th { text-align: left; padding: 8px; border-bottom: 2px solid #e5e7eb }
td { padding: 24px 8px; text-align: center; color: #6b7280 }
</style>
<table class="es" style="max-width:none"><thead><tr><th>Client</th><th>Amount</th><th>Due</th></tr></thead><tbody><tr><td colspan="3">No unpaid invoices. <a href="#">See paid invoices</a></td></tr></tbody></table>
A heading that names the situation, one sentence that explains it or what will appear here, and one action. Everything else, such as artwork, tips or links to help, is optional and should not push the action off screen on a phone.
Write the heading from the user's side. Your project list is empty reads as blame; No projects yet reads as a starting point.
Every list, table, chart and search in a product needs at least two empty versions: before anything exists and when a filter hides everything. Designing them alongside the full state is cheaper than patching them after users complain about blank screens.
It is the screen or panel shown when a list, table, dashboard or search has nothing to display. Good ones explain why and give the next action; poor ones show blank space or a bare No data.
Use a real heading and text, not just an image. Mark decorative artwork with empty alt text. If the empty message appears after a filter or search without a page load, place it inside an element with role="status", which has an implicit polite live setting, and do not move focus to it.
It can help on first use, for example a demo project the user can open and delete. Label it clearly as an example so nobody mistakes it for their own data.
Repeat the term, say nothing matched, and suggest fixes: check spelling, remove a filter, or browse a category. A one-click Clear filters button is the most useful single action.
An empty state means there is genuinely nothing to show. An error means there might be data but it could not be loaded. Say which one it is, because telling someone they have no orders when the server failed is alarming.
Related: 404 page examples, Thank you page examples, Website accessibility checklist, CSS button states, shadcn/ui examples.
Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.
We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.