EmptyState
For empty lists, searches with no results and first-run screens — an icon, a title, a description and actions.
Buyurtmalar hali yo'q
Birinchi buyurtma kelganda shu yerda ko'rinadi.
'use client';
import { Button, EmptyState } from '@akhatmirzo/ui';
import { Inbox, Plus } from 'lucide-react';
export default function EmptyStateBasic() {
return (
<EmptyState
icon={<Inbox />}
title="Buyurtmalar hali yo'q"
description="Birinchi buyurtma kelganda shu yerda ko'rinadi."
action={
<Button variant="primary" leftIcon={<Plus />}>
Mahsulot qo'shish
</Button>
}
secondaryAction={<Button variant="ghost">Qo'llanma</Button>}
/>
);
}
Import
import { EmptyState } from '@akhatmirzo/ui';When to use
- When a list or table is empty — "No orders yet". Instead of blank space, explain what happened and what to do next.
- When a search or filter returns nothing — suggest changing the query or clearing filters.
- On first run — guide people to their first action (
size="lg"). - One main action —
action(primary), with an optionalsecondaryAction(ghost). - Keep the title short and the description useful — not "Nothing here", but "Your first order will show up here".
No search results
bordered adds a dashed border for use inside a section.
Hech narsa topilmadi
"Namangan" bo'yicha natija yo'q. So'zni o'zgartirib ko'ring.
'use client';
import { Button, EmptyState, Input } from '@akhatmirzo/ui';
import { SearchX } from 'lucide-react';
import { useState } from 'react';
export default function EmptyStateSearch() {
const [query, setQuery] = useState('Namangan');
return (
<div className="flex w-full max-w-md flex-col gap-3">
<Input
aria-label="Shahar qidirish"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Shahar nomi"
/>
<EmptyState
size="sm"
bordered
icon={<SearchX />}
title="Hech narsa topilmadi"
description={`"${query}" bo'yicha natija yo'q. So'zni o'zgartirib ko'ring.`}
action={
<Button size="sm" onClick={() => setQuery('')}>
Qidiruvni tozalash
</Button>
}
/>
</div>
);
}
Sizes
size: sm has 24px vertical padding, md (default) 40px and lg 64px, with a 64px icon circle
and a larger title.
Kichik
sm
O'rta
md
Katta
lg
'use client';
import { EmptyState } from '@akhatmirzo/ui';
import { FolderOpen } from 'lucide-react';
export default function EmptyStateSizes() {
return (
<div className="grid w-full gap-4 sm:grid-cols-3">
<EmptyState bordered size="sm" icon={<FolderOpen />} title="Kichik" description="sm" />
<EmptyState bordered size="md" icon={<FolderOpen />} title="O'rta" description="md" />
<EmptyState bordered size="lg" icon={<FolderOpen />} title="Katta" description="lg" />
</div>
);
}
With DataTable
When a DataTable is empty, its empty slot draws this same layout. Pass icon, title,
description and action to empty, just like with EmptyState.
| № | Mijoz | Summa |
|---|---|---|
Buyurtmalar hali yo'q Birinchi buyurtma kelganda shu yerda ko'rinadi. | ||
'use client';
import { Button, DataTable, type DataTableColumn } from '@akhatmirzo/ui';
import { Inbox, Plus } from 'lucide-react';
interface Order {
id: number;
customer: string;
total: string;
}
const columns: DataTableColumn<Order>[] = [
{ key: 'id', header: '№' },
{ key: 'customer', header: 'Mijoz' },
{ key: 'total', header: 'Summa' },
];
const orders: Order[] = [];
export default function EmptyStateDataTable() {
return (
<DataTable
className="w-full"
label="Buyurtmalar"
data={orders}
columns={columns}
empty={{
icon: <Inbox />,
title: "Buyurtmalar hali yo'q",
description: "Birinchi buyurtma kelganda shu yerda ko'rinadi.",
action: (
<Button size="sm" variant="primary" leftIcon={<Plus />}>
Buyurtma qo'shish
</Button>
),
}}
/>
);
}
Props
EmptyState accepts every other <div> attribute (except title, which is used as a prop).
| Prop | Type | Default | Description |
|---|---|---|---|
titlerequired | ReactNode | — | Title |
description | ReactNode | — | Short description (max 40ch wide) |
icon | ReactNode | — | Shown in a 48px circle (64px on lg) |
action | ReactNode | — | Main action |
secondaryAction | ReactNode | — | Secondary action |
size | 'sm' | 'md' | 'lg' | 'md' | Vertical padding: 24 / 40 / 64px |
bordered | boolean | false | Dashed border and radius (for use inside a section) |
headingLevel | 2 | 3 | 4 | 5 | 6 | 3 | Title tag (h2–h6) |
Data attributes
On the root: data-size and data-bordered (when bordered). emptyStateVariants is exported too,
so you can apply the styles to another element.
Accessibility
- The title is a real
h*element —h3by default. SetheadingLevelto fit your page so the heading order stays intact. - The icon is decorative — it's
aria-hiddentogether with its circle. - Actions are your own buttons and work with the keyboard as usual. On narrow screens (< 640px) they stack and go full width.
- If the content changes dynamically (search) and you want it announced, put
role="status"on the surrounding container.