Empty fills a container that would otherwise be blank: a framed icon, a short headline, a line of supporting copy, and room for one or two actions that lead the user out of the empty state. It’s the component you reach for when the zero case is a normal, expected outcome rather than an error.
Don’t use Empty for failures or missing permissions — those want an
<Alert> with recovery context. Use Empty when the region simply has no
data yet and the user can do something about it: create the first resource,
adjust a filter, connect an integration.
Import
import { Empty } from "@unkey/ui";
The component is a compound: Empty is the wrapper, and Empty.Icon,
Empty.Title, Empty.Description, and Empty.Actions are the slots.
Default
With no icon child, Empty.Icon renders the Ufo glyph from @unkey/icons
inside a framed tile with crosshair dividers. Use the default when the
region is empty in a generic, friendly way and no specific icon adds
meaning.
Nothing here yet
When you create your first resource, it will show up here.
Custom icon
Pass any icon from @unkey/icons as the child of Empty.Icon to replace
the default. The framed tile, the crosshair dividers, and the 28px sizing
are preserved — only the glyph changes.
No matches
We couldn’t find anything for that query. Try a shorter search term or clear your filters.
With actions
Empty.Actions is a centered flex row with a small top margin and a gap
between children. Put one primary action and, optionally, a secondary
outline or ghost button beside it. Two actions is the ceiling — more than
that turns the empty state into a menu.
No keys yet
Create your first API key to start authenticating requests against this workspace.
Headline only
Every slot is optional. For dense layouts (a small table cell, a sidebar panel) you can drop the description and keep just the icon and title.
No activity in the last 24 hours
Accessibility
Empty is a plain <div> with no implicit role. It’s a visual affordance,
not a live region — screen readers read it as the heading and paragraph
inside.
Empty.Title renders as <h2>. If the empty state is nested below an
existing <h2> on the page, the heading hierarchy will skip. In that case,
override with a wrapping <h3> at the call site and pass plain text into
Empty.Title’s children, or restyle via className.
Any button placed inside Empty.Actions keeps its native semantics; follow
the usual <Button> accessibility rules (accessible name, sensible
aria-label for icon-only buttons).
Props
Empty
The outer wrapper. A flex column that fills its parent (h-full w-full)
and centers its children vertically and horizontally with 2rem of padding.
className string Optional Additional Tailwind classes. Override h-full when the empty state
should size to its content (h-auto), or tighten padding (p-4) in
compact layouts.
children ReactNode Optional Typically <Empty.Icon>, <Empty.Title>, <Empty.Description>, and
<Empty.Actions>, in that order. All are optional.
...rest HTMLAttributes<HTMLDivElement> Optional Standard div attributes pass through — useful for role="status" when
you want assistive tech to announce the empty state as it appears.
Empty.Icon
A 7rem square tile containing a 4rem framed glyph, flanked by thin
crosshair dividers. If no child is provided, renders the Ufo icon from
@unkey/icons at iconSize="2xl-regular".
className string Optional Additional Tailwind classes applied to the outer 7rem container. The inner framed tile’s size and border are not exposed — restyle with a wrapping element if you need a different frame.
children ReactNode Optional The glyph to render inside the framed tile. Any icon from
@unkey/icons works; the tile constrains SVGs to 1.75rem
([&_svg]:size-7). When omitted, defaults to <Ufo iconSize="2xl-regular" />.
Empty.Title
Renders as <h2> with semi-bold weight, 15px size, and 1.5rem leading. The
headline sits 0.75rem below the icon.
className string Optional Additional Tailwind classes. Override text-accent-12 when the empty
state is placed on a colored surface, or tighten mt-3 when combined
with a larger icon.
children ReactNode Optional The headline text. Keep it to a short phrase — “No keys yet”, “Nothing
to show”. Long sentences belong in <Empty.Description>.
...rest HTMLAttributes<HTMLHeadingElement> Optional Standard heading attributes pass through (id for aria-labelledby,
etc.).
Empty.Description
Renders as <p> in the muted text-accent-11 color at 12px size with
1.5rem leading and a 0.25rem top margin.
className string Optional Additional Tailwind classes. Widen with max-w-sm mx-auto when the
copy wraps awkwardly in a wide container.
children ReactNode Optional Supporting copy — one or two sentences that explain the empty state and hint at the next step.
...rest HTMLAttributes<HTMLParagraphElement> Optional Standard paragraph attributes pass through.
Empty.Actions
Horizontal flex row, centered, with a 1rem gap between children and a
0.5rem top margin. Intended for one or two <Button>s.
className string Optional Additional Tailwind classes. Switch to flex-col gap-2 for stacked
actions in narrow containers.
children ReactNode Optional Usually one primary <Button> and, optionally, a secondary outline
or ghost button beside it.
...rest HTMLAttributes<HTMLDivElement> Optional Standard div attributes pass through.
Related
- Alert — for failure or permission states that need to announce themselves.
- Card — when the empty region is a panel that should carry its own border.
- Button — for the action(s) inside
<Empty.Actions>.