Empty state
An empty state fills a region that loaded with nothing to show. It says why the region is empty and offers the next step.
Create your first project
A project is where your team's work lives. Set one up to get started.<tk-empty-state> <tk-icon slot="media" name="plus"></tk-icon> <h3 slot="title">Create your first project</h3> A project is where your team's work lives. Set one up to get started. <tk-button slot="actions" variant="primary">New project</tk-button> </tk-empty-state>
Anatomy
| Part | What it is |
|---|---|
tk-empty-state |
the element; a centered column up to 30rem wide |
media slot |
an optional icon or picture; decorative |
title slot |
an optional title; put a real heading in it |
| default slot | the body: a short explanation |
actions slot |
optional actions, centered under the body |
Every slot is optional, and an empty one takes no space.
Use cases
Every case uses the same element. The media, the words, and the action tell them apart.
| Case | Media | Title | Action |
|---|---|---|---|
| First run | a larger tk-icon or picture |
"Create your first project" | one primary Create or Add |
| Empty list | a tk-icon |
"No saved items yet" | Add, or none |
| No results | search |
"No results for 'invoce'" | Clear filters or Edit search |
| Failed load | error |
"Something went wrong" | Retry, and maybe a support link |
| All done | none, or a glyph | "You're all caught up" | usually none |
Something went wrong
We couldn't load your invoices. Check your connection and try again.<tk-empty-state> <tk-icon slot="media" name="error"></tk-icon> <h3 slot="title">Something went wrong</h3> We couldn't load your invoices. Check your connection and try again. <tk-button slot="actions" variant="primary">Retry</tk-button> <tk-link slot="actions" treatment="quiet" href="/support">Contact support</tk-link> </tk-empty-state>
- Keep an error empty state neutral. There is no red or green version; the words and the Retry action carry it.
- After a search, offer a way out, such as Clear filters. Never "Add your first".
Sizes
<tk-empty-state compact> <tk-icon slot="media" name="search"></tk-icon> <span slot="title">No results for 'quarterly'</span> Try a different search, or clear the filters. <tk-button slot="actions" size="small">Clear filters</tk-button> </tk-empty-state>
| Padding (block × inline) | Media | Title | Body | |
|---|---|---|---|---|
| default | space-48 × space-24 |
3rem | font-size-xl |
font-size-md |
compact |
space-24 × space-16 |
2rem | font-size-lg |
font-size-sm |
Use the default to fill a page or a large panel, and compact inside a card, panel, or
table. Put the element in a region with a height and it centers vertically.
Media
- A
intk-iconslot="media"sizes to the media box and takes the muted icon color. A picture sizes itself. - Media is hidden from screen readers unless you name it with
alt,aria-label, oraria-labelledby. Name it only if it adds meaning the words don't. - No illustrations ship with Thykes; bring your own if you need one.
When to use
- Use an empty state when a region has loaded and is empty: a first run, no search results, an empty list, or a failed load. It replaces the region's content.
- Use a
Skeleton while the content is still loading. - Use a
Section message for a note about content that is still there. - Use a
Banner for a message about the whole app. - For a whole-page error such as a 404, build the page yourself and use an empty state as its centered body.
Content
- Say why the region is empty and how to start: "Create your first project".
- After a search, help the reader out: check the spelling, try a broader term.
- End with a verb in the action: "Clear filters", "Retry". Use one primary action and at most one secondary.
- Make the words work without the picture. No exclamation marks, no blame.
More in
Do / Don't
| ✅ Do | ❌ Don't |
|---|---|
| Say why it's empty and what to do next | Leave a blank panel with no way forward |
| Offer Clear filters after a search | Offer "Add your first" after a search |
| Keep a failed load neutral, with Retry | Color the empty state red or green |
| Use a Skeleton while loading | Show an empty state before the data arrives |
Announce "No results" with role="status" |
Expect the empty state to announce itself |
Related
Skeleton : the placeholder while content loads.Section message : a note over content that is still there.Banner : a message about the whole app.Button ,Link , andIcon : what goes in the slots.
API
Attributes
| Attribute | Type | Default | What it does |
|---|---|---|---|
compact |
boolean | false |
tighter padding and a smaller media and title |
Slots
| Slot | Content |
|---|---|
media |
a tk-icon or your picture; hidden unless named |
title |
a heading (<h2>–<h6>) or a <span> |
| default | the body text |
actions |
a primary tk-button and an optional quiet tk-link |
Events
None.
CSS
- Parts:
empty-state,media,title,body,actions. --tk-empty-state-max-width: the column's maximum width,30remby default.--tk-empty-state-media-size: the media box,3remby default and2remwithcompact.
Tokens
| Part | Token |
|---|---|
| title | text/default |
| body | text/secondary |
tk-icon media |
icon/secondary |
| gap | space-16, or space-12 with compact; actions space-12 |
The element has no fill, so it sits on whatever surface is around it.
Accessibility
Built in:
- It has no role and is not a live region; it's read in page order like any content.
- It never takes focus. The actions are ordinary buttons and links.
- Unnamed media is hidden from screen readers.
- Text holds AA contrast in every theme.
Your part:
- Use a real heading in
title, at the right level for the page. - After a search, announce the result yourself: a visually hidden
role="status"on the results region that says "No results found". TheSkeleton page shows the pattern. - Put the meaning in the words, not the picture.