Blank
Designed empty/error state for tables and lists, with optional actions.
import { Blank }from "@/components/ui"
Empty state
No users yet
Invite your first teammate to get started.
Full source
The complete component, read from src/components/ui/blank.tsx.
blank.tsx
"use client";
import type { LucideIcon } from "lucide-react";
import { cn } from "@/lib/utils";
import { Button } from "./button";
type BlankTone = "rose" | "amber" | "neutral";
interface BlankProps {
icon?: LucideIcon;
title: string;
body: string;
primary?: string;
secondary?: string;
mono?: string;
tone?: BlankTone;
onPrimary?: () => void;
onSecondary?: () => void;
}
const TONE_TEXT: Record<BlankTone, string> = {
rose: "text-error",
amber: "text-warning",
neutral: "text-text-tertiary",
};
export function Blank({
icon: Icon,
title,
body,
primary,
secondary,
mono,
tone = "neutral",
onPrimary,
onSecondary,
}: BlankProps) {
return (
<div className="flex flex-col items-center px-6 py-16 text-center">
{Icon && <Icon size={22} className={TONE_TEXT[tone]} aria-hidden />}
<p className="mt-3 text-base font-medium text-text">{title}</p>
<p className="mx-auto mt-1 max-w-sm text-sm leading-relaxed text-text-secondary">{body}</p>
<div className="mt-4 flex flex-wrap items-center justify-center gap-2">
{primary && (
<Button onClick={onPrimary}>{primary}</Button>
)}
{secondary && (
<Button variant="secondary" onClick={onSecondary}>{secondary}</Button>
)}
</div>
{mono && <p className="mt-5 font-mono text-[11px] text-text-tertiary">{mono}</p>}
</div>
);
}