Component
Empty state
What a region shows when it has nothing in it: why, and the one thing to do next.
Plain-text source, for agents and clipboard use: /components/source/empty-state.txt
When to use it
Replaces a blank table, list or panel with a short heading that says what is missing, one sentence on why or what fills it, and at most one action. It sits inside the surface that would have held the content, so the page keeps its structure. A first-use state invites the first record; a filtered state offers to clear the filters; a table keeps its headers and spans the empty state across every column.
Examples
First use, in a card
The card keeps its title, so the page still reads as the same page. The body says what fills the region and the button does it.
Departures
No departures yet
Add the first departure for Golden Circle Classic, and it will appear here with its allocation and guide.
<section class="flux-card" aria-labelledby="departures-title">
<h2 class="flux-card__title" id="departures-title">Departures</h2>
<div class="flux-empty">
<svg class="flux-empty__icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2.5" y="3.5" width="11" height="10" rx="1" /><path d="M5.5 2v3M10.5 2v3M2.5 7h11" /></svg>
<h3 class="flux-empty__title">No departures yet</h3>
<p class="flux-empty__body">Add the first departure for Golden Circle Classic, and it will appear here with its allocation and guide.</p>
<div class="flux-empty__actions">
<button class="flux-button" type="button">Add departure</button>
</div>
</div>
</section>Filtered to nothing
When filters hide every row, say so and offer to clear them. The action is secondary: nothing is being created.
No bookings match these filters
Nothing departs in October with the status Awaiting supplier.
<div class="flux-empty flux-empty--compact">
<svg class="flux-empty__icon" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M2.5 3.5h11l-4.25 5v4l-2.5 1v-5z" /></svg>
<h3 class="flux-empty__title">No bookings match these filters</h3>
<p class="flux-empty__body">Nothing departs in October with the status Awaiting supplier.</p>
<div class="flux-empty__actions">
<button class="flux-button flux-button--secondary" type="button">Clear filters</button>
</div>
</div>In a table
The headers stay, so the shape of the data is still clear. One cell spans every column and holds a compact empty state.
| Reference | Supplier | Status | Rooms |
|---|---|---|---|
|
No open requests Every supplier has answered. New requests appear here when a booking needs space confirmed. |
|||
<div class="flux-table-wrap">
<table class="flux-table">
<caption class="flux-visually-hidden">Supplier requests</caption>
<thead>
<tr>
<th scope="col">Reference</th>
<th scope="col">Supplier</th>
<th scope="col">Status</th>
<th scope="col" data-numeric>Rooms</th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="4">
<div class="flux-empty flux-empty--compact">
<p class="flux-empty__title">No open requests</p>
<p class="flux-empty__body">Every supplier has answered. New requests appear here when a booking needs space confirmed.</p>
</div>
</td>
</tr>
</tbody>
</table>
</div>Anatomy
| Part | Description |
|---|---|
| Icon | Optional. A 32px line icon in icon-secondary that names the kind of thing missing. Never an illustration. |
| Title | A heading at the level the region needs, or a paragraph inside a table cell. States what is missing. |
| Body | One sentence, held to the reading measure. |
| Actions | At most one primary action, or a secondary action for a filtered state. |
API
| Name | Kind | Description |
|---|---|---|
flux-empty | class | The empty state. Place it inside the surface that would have held the content. |
flux-empty__icon | class | On the svg. Optional. |
flux-empty__title | class | On a heading, or a p inside a table cell. |
flux-empty__body | class | One sentence. |
flux-empty__actions | class | The action row. |
flux-empty--compact | class | Less vertical padding, for table cells, panels and filtered results. |
States
| State | Treatment |
|---|---|
| First use | Nothing has been created. One primary action creates the first record. |
| Filtered | Records exist but are hidden. A secondary action clears the filters. |
| Done | Nothing is waiting, which is good news. No action, and a sentence saying what would bring something back. |
Keyboard
| Keys | Action |
|---|---|
Tab | Reaches the action, if there is one. The rest is not interactive. |
Accessibility
- Use a heading for the title when the region has headings of its own, at the next level down.
- When a search or filter empties the results, announce it through the live result count that the table or search already has.
- The icon is decorative and carries aria-hidden.
Tokens
The tier-3 and tier-2 tokens this component binds to. Change the token, not the component.
- --flux-empty-padding | -gap | -measure
- --flux-empty-icon | -icon-size
- --flux-empty-title-size | -body
Do and don’t
Do
- Say what is missing in the title and what fills it in the body.
- Keep the region’s own heading, headers and toolbar in place.
- Offer the action that ends the empty state: create the first one, or clear the filters.
Don’t
- Do not add an illustration, a mascot or a gradient panel.
- Do not offer more than one primary action.
- Do not centre more than the title and the one sentence below it.