Prisma
Live Preview

No results found

We couldn't find any items matching your search. Try adjusting your filters or create a new item.

Empty State Component

Skill này hướng dẫn tạo component Empty State — placeholder pattern khi list/table/section không có dữ liệu, với icon, title, description, và action CTA.

1. Mục tiêu (Objective)

Tạo Empty State pattern — hiển thị khi list/table/section không có dữ liệu, với icon, title, description, và action CTA. Hỗ trợ 3 sizes: inline, section, full page.

2. AI Context & Intent (Ngữ cảnh cho AI)

Khi nào dùng Empty State?

  • No data: Table/list trống, chưa có items
  • No results: Search/filter trả về 0 kết quả
  • First time: Onboarding, chưa tạo item nào
  • Error fallback: Data fetch failed

⚠️ Phân biệt Empty State vs Skeleton vs Error Page (QUAN TRỌNG)

Tiêu chí Empty State Skeleton Error Page
Bản chất No data available Loading in progress System error
When After load, 0 results During loading Request failed
Action Create/Add/Filter CTA None (wait) Retry/Back CTA
Tone Encouraging Neutral Apologetic
Ví dụ "No orders yet" + Add Shimmer placeholders "500 Server Error"

Decision Tree cho AI

text
Data trống hoặc unavailable?
├─ Đang loading → Skeleton hoặc Spinner
├─ Load xong, 0 items → Empty State
│   ├─ Chưa có data lần đầu → Empty State + "Get started" CTA
│   │   ├─ Trong card/panel → Empty State (sm)
│   │   ├─ Section chính → Empty State (md)
│   │   └─ Full page (landing) → Empty State (lg)
│   │
│   ├─ Search/filter 0 results → Empty State + "Clear filters" CTA
│   └─ Feature chưa enable → Empty State + "Enable" CTA
│
├─ Error (network, server) → Error Page / Alert
│   ├─ Inline error → Alert component
│   └─ Full page → Error page
│
└─ Maintenance → System status page

3. Anatomy

text
┌──────────────────────────────────────┐
│                                      │
│          ┌────────────┐              │
│          │  📋 icon   │              │ ← Icon: --muted-foreground
│          └────────────┘              │    decorative, aria-hidden
│                                      │
│        No orders yet                 │ ← Title: --foreground
│                                      │    --font-weight-semibold
│   Start by creating your first       │ ← Description: --muted-foreground
│   order to see it appear here.       │    --font-size-sm
│                                      │
│     [ Create Order ]  [ Learn More ] │ ← Actions: primary + outline buttons
│                                      │
└──────────────────────────────────────┘

4. Platform Mapping

Platform Component Key Difference
Web EmptyState (pattern) Centered layout with illustration
iOS ContentUnavailableView (iOS 17+) System-provided empty states
Android (M3) Custom pattern No M3 spec, follow guidelines
Carbon ❌ (pattern, not component) Documented as pattern

Cross-platform note: Empty state là UX pattern, không phải UI component cụ thể. Token file cung cấp consistent sizing/spacing.

5. Sizes

Size Use case
sm Inline trong card hoặc panel
md Section-level empty state
lg Full page empty state

5.4. Slot Map (Figma ↔ Code)

📎 Source: slot-manifest.jsonempty-state · Layer: card

Figma Slot data-slot CSS Class Required Accepts
Root empty-state .empty-state
Illustration empty-state-illustration image, icon (large)
Title empty-state-title text
Description empty-state-description text
Action empty-state-action button, link

6. Token Mapping

📦 Atomic Mapping: Xem ATOMIC-MAPPING.md → mục empty-state — UI Layer: Card (in-flow), Density Tier: section.

Icon fg dùng --muted-foreground, title fg dùng --foreground, description fg dùng --muted-foreground. Component token JSON files đã deprecated.

7. Props & API

typescript
interface EmptyStateProps {
  icon?: ReactNode;            // Illustration or icon
  title: string;
  description?: string;
  primaryAction?: {
    label: string;
    onClick: () => void;
  };
  secondaryAction?: {
    label: string;
    onClick: () => void;
  };
  size?: 'sm' | 'md' | 'lg';
}

8. Accessibility (a11y)

  • Container: Contextual role (inside table = <td colspan>, standalone = <div>).
  • Icon: aria-hidden="true" (decorative).
  • Action buttons: Standard button a11y.

9. Best Practices & Rules

  • Context-aware messaging: "No transactions found" vs "No results for 'xyz'" vs "Get started by..."
  • Action-oriented: Always provide at least 1 action CTA.
  • Illustration: Use consistent illustration style. Avoid generic "empty box" images.
  • Icon: Illustration icon CHỈ dùng Lucide icon từ assets/icons/ (vd: file, search, inbox). CẤM dùng text emoji. Xem icon.md mục 10.
  • Không Hardcode: Mọi giá trị từ Token.

10. Example Usage

jsx
{/* First-time empty - full page */}
<EmptyState
  icon={<Icon name="package" size="xl" />}
  title="No orders yet"
  description="Start by creating your first order to track deliveries."
  primaryAction={{ label: "Create Order", onClick: createOrder }}
  secondaryAction={{ label: "Learn More", onClick: openDocs }}
  size="lg"
/>

{/* Search no results */}
<EmptyState
  icon={<Icon name="search" size="lg" />}
  title="No results found"
  description={'No items match "' + query + '". Try different keywords.'}
  primaryAction={{ label: "Clear Filters", onClick: clearFilters }}
  size="md"
/>

{/* Inline card empty */}
<Card>
  <EmptyState
    icon={<Icon name="inbox" size="md" />}
    title="No notifications"
    size="sm"
  />
</Card>