🔥 Oxide UI v0.1.0 — Dark mode only, copy-paste ready. Get started →
Skip to content

Empty State

<div>

Shown when a data set is empty, a search returns nothing, or a feature hasn't been used yet. A good empty state explains what's missing and offers a clear action.

Overview

Preview

No files yet

Upload your first file to get started. Supports PNG, JPG, PDF up to 10MB.

No results found

No components match "datepicker". Try a different search term.

Default empty state

Preview

No files yet

Upload your first file to get started. Supports PNG, JPG, PDF up to 10MB.

html
<div class="flex flex-col items-center justify-center rounded-xl border border-dashed border-zinc-800 px-8 py-14 text-center">
  <!-- Icon -->
  <div class="flex h-12 w-12 items-center justify-center rounded-full bg-zinc-800/80 mb-4">
    <svg class="h-5 w-5 text-zinc-500" ...></svg>
  </div>

  <!-- Copy -->
  <p class="text-sm font-semibold text-zinc-300">No files yet</p>
  <p class="mt-1 text-xs text-zinc-600 max-w-xs">
    Upload your first file to get started. Supports PNG, JPG, PDF up to 10MB.
  </p>

  <!-- Action -->
  <button class="mt-4 inline-flex items-center gap-2 rounded-md bg-[#D40C37] px-4 py-2 text-xs font-medium text-white hover:bg-[#b50a2f] transition-colors">
    Upload file
  </button>
</div>

No search results

Preview

No results found

Nothing matched "datepicker". Try a different term.

html
<div class="flex flex-col items-center justify-center rounded-xl border border-dashed border-zinc-800 px-8 py-14 text-center">
  <div class="...mb-4">
    <!-- Search icon -->
  </div>
  <p class="text-sm font-semibold text-zinc-300">No results found</p>
  <p class="mt-1 text-xs text-zinc-600">
    Nothing matched <span class="font-mono text-zinc-500">"{{ query }}"</span>. Try a different term.
  </p>
  <button class="mt-4 rounded-md border border-zinc-700 px-4 py-2 text-xs font-medium text-zinc-400 hover:bg-zinc-800 transition-colors">
    Clear search
  </button>
</div>

In a table

html
<table class="w-full">
  <thead><!-- ... --></thead>
  <tbody>
    <!-- No data row -->
    <tr v-if="rows.length === 0">
      <td :colspan="columns.length" class="px-5 py-16 text-center">
        <div class="flex flex-col items-center gap-3">
          <div class="flex h-10 w-10 items-center justify-center rounded-full bg-zinc-800/80">
            <svg class="h-4 w-4 text-zinc-500" ...></svg>
          </div>
          <div>
            <p class="text-sm font-medium text-zinc-400">No records found</p>
            <p class="mt-0.5 text-xs text-zinc-600">Adjust your filters or add new data.</p>
          </div>
        </div>
      </td>
    </tr>
    <!-- Data rows -->
    <tr v-for="row in rows" :key="row.id"><!-- ... --></tr>
  </tbody>
</table>

Minimal (no icon)

Preview

No notifications

You're all caught up.

html
<div class="flex flex-col items-center justify-center py-12 text-center">
  <p class="text-sm font-medium text-zinc-500">No notifications</p>
  <p class="mt-1 text-xs text-zinc-700">You're all caught up.</p>
</div>

Writing good empty states

  • Be specific — "No thumbnails downloaded yet" beats "Nothing here"
  • Explain why — "Your API key hasn't been used this month" adds context
  • Give a next step — a primary action button converts empty states into onboarding moments
  • Don't apologise — don't say "Sorry, no results found"
  • Match the context — a search empty state needs "Clear search", a first-run needs "Get started"

Accessibility notes

  • Empty states are purely informational — no special ARIA is required
  • If the empty state replaces a live region (like a table), ensure aria-live="polite" is on the container so screen readers announce the state change

Released under the MIT License.