Import
import {
Empty,
EmptyContent,
EmptyDescription,
EmptyHeader,
EmptyMedia,
EmptyTitle,
} from "@timelycare/helix-ui"
Props
interface EmptyProps extends React.HTMLAttributes<HTMLDivElement> {
className?: string
children: React.ReactNode
}
interface EmptyHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
className?: string
children: React.ReactNode
}
interface EmptyMediaProps extends React.HTMLAttributes<HTMLDivElement> {
variant?: "default" | "icon"
className?: string
children: React.ReactNode
}
interface EmptyTitleProps extends React.HTMLAttributes<HTMLHeadingElement> {
className?: string
children: React.ReactNode
}
interface EmptyDescriptionProps extends React.HTMLAttributes<HTMLParagraphElement> {
className?: string
children: React.ReactNode
}
interface EmptyContentProps extends React.HTMLAttributes<HTMLDivElement> {
className?: string
children: React.ReactNode
}
Styling
| Property | Value | Tailwind |
|---|---|---|
| Layout | Flex column, centered | flex flex-col items-center justify-center |
| Text align | Center | text-center |
| Gap (sections) | 16px | gap-4 |
| Padding | 24px | p-6 |
Typography
| Element | Font | Size | Color |
|---|---|---|---|
| Title | Adelle Sans Semibold | 16px (text-base) | text-foreground |
| Description | Adelle Sans Regular | 14px (text-sm) | text-muted-foreground |
Media
| Variant | Size | Style |
|---|---|---|
icon | 48px | size-12 text-muted-foreground — icon centered in a muted circular background |
default | Flexible | Renders children as-is (avatars, images, etc.) |
Variants
Empty is a single-variant component. Visual variation comes from composition of sub-components and media variants.
Common Patterns
Basic Empty State
<Empty>
<EmptyHeader>
<EmptyMedia variant="icon">
<InboxIcon />
</EmptyMedia>
<EmptyTitle>No messages</EmptyTitle>
<EmptyDescription>You don't have any messages yet.</EmptyDescription>
</EmptyHeader>
<EmptyContent>
<Button>Send a message</Button>
</EmptyContent>
</Empty>
With Actions
<Empty>
<EmptyHeader>
<EmptyMedia variant="icon">
<FolderIcon />
</EmptyMedia>
<EmptyTitle>No Projects Yet</EmptyTitle>
<EmptyDescription>
You haven't created any projects yet. Get started by creating your first project.
</EmptyDescription>
</EmptyHeader>
<EmptyContent>
<div className="flex gap-2">
<Button>Create Project</Button>
<Button variant="outline">Import Project</Button>
</div>
</EmptyContent>
<Button variant="link" className="text-muted-foreground" size="sm" asChild>
<a href="/docs">Learn More <ArrowUpRightIcon /></a>
</Button>
</Empty>
With Avatar
<Empty>
<EmptyHeader>
<EmptyMedia variant="default">
<Avatar className="size-12">
<AvatarImage src="/user.png" />
<AvatarFallback>JD</AvatarFallback>
</Avatar>
</EmptyMedia>
<EmptyTitle>User Offline</EmptyTitle>
<EmptyDescription>
This user is currently offline. You can leave a message.
</EmptyDescription>
</EmptyHeader>
<EmptyContent>
<Button size="sm">Leave Message</Button>
</EmptyContent>
</Empty>
404 / Search Empty State
<Empty>
<EmptyHeader>
<EmptyTitle>404 - Not Found</EmptyTitle>
<EmptyDescription>
The page you're looking for doesn't exist. Try searching below.
</EmptyDescription>
</EmptyHeader>
<EmptyContent>
<InputGroup className="sm:w-3/4">
<InputGroupInput placeholder="Try searching..." />
<InputGroupAddon>
<SearchIcon />
</InputGroupAddon>
</InputGroup>
</EmptyContent>
</Empty>
Icon Selection Guide
| Context | Icon |
|---|---|
| No data | Inbox |
| No search results | Search |
| No files/documents | FileText |
| No notifications | Bell |
| No users | Users |
| No messages | MessageSquare |
Accessibility
- Use semantic heading elements via
EmptyTitle(renders as heading) EmptyDescriptionprovides context for screen readers- Action buttons within
EmptyContentmust be keyboard accessible - For icon-only media, the icon is decorative — screen readers skip it in favor of the title
Gotchas
| Problem | Solution |
|---|---|
| Empty state not centered vertically | Ensure parent container has min-h-[300px] or similar height constraint |
| Icon too small or large | Use variant="icon" on EmptyMedia for consistent size-12 icon container |
| Multiple action buttons misaligned | Wrap in a div with flex gap-2 inside EmptyContent |
| Description text too wide | Constrain the parent Empty width or use max-w-md on description |
See Also
- Related Components: Skeleton (loading placeholder), Card (container for empty states)
- Patterns: Component Match — When to use Empty vs Skeleton
Last updated: February 19, 2026