Live Preview
Saved successfully
Connection failed
Warning
New update available
Toast Component Generation Skill
Skill này hướng dẫn bạn (AI Agent) tạo component Toast / Notification — thông báo tạm thời tự động dismiss.
1. Mục tiêu (Objective)
Tạo component Toast (single) + Toast Container (stacking), hỗ trợ auto-dismiss, manual close, action button, và tích hợp 100% semantic color tokens.
2. AI Context & Intent (Ngữ cảnh cho AI)
Khi nào dùng Toast?
- Feedback ngắn sau action: "Đã lưu!", "Đã copy link!", "Gửi thành công"
- Error tạm thời: "Không thể kết nối"
- Undo feedback: "Đã xoá. Hoàn tác?"
⚠️ Phân biệt Toast vs Alert vs Modal (QUAN TRỌNG)
| Tiêu chí | Toast | Alert | Modal |
|---|---|---|---|
| Duration | Tạm thời (3–5s auto-dismiss) | Persistent (luôn hiện) | User phải close |
| Position | Fixed corner (top-right / bottom) | Inline trong page | Center overlay |
| Blocking | ❌ Không chặn | ❌ Không chặn | ✅ Chặn |
| Khi nào | Action feedback | Info quan trọng cần đọc lại | Cần confirm/input |
| Ví dụ | "Đã lưu!" | "Account chưa verify" | "Xác nhận xoá?" |
Decision Tree cho AI
text
Cần thông báo?
├─ Feedback tạm thời sau action → Toast
│ ├─ Thành công → variant="success"
│ ├─ Lỗi có thể retry → variant="destructive" + action
│ ├─ Cảnh báo nhẹ → variant="warning"
│ └─ Info trung lập → variant="default"
├─ Info persistent trên page → Alert
├─ Cần action bắt buộc → Modal
└─ Cần user confirm → Modal (alert dialog)
3. Ngữ nghĩa & Phân loại (Semantics)
3.1. Variants
| Variant | Mục đích | Icon (Lucide) | Tokens |
|---|---|---|---|
default |
Thông tin trung lập | info (info.svg) |
base.surface, base.surface-foreground |
success |
Action thành công | circle-check (circle-check.svg) |
base.success-muted, base.success-muted-foreground |
warning |
Cảnh báo nhẹ | triangle-alert (triangle-alert.svg) |
base.warning-muted, base.warning-muted-foreground |
destructive |
Lỗi / thất bại | circle-x (circle-x.svg) |
base.destructive-muted, base.destructive-muted-foreground |
info |
Thông tin bổ sung | info (info.svg) |
base.info-muted, base.info-muted-foreground |
3.2. Position (Container level)
| Position | Mô tả | Use case |
|---|---|---|
top-right |
Góc trên phải (mặc định desktop) | Standard |
top-center |
Trung tâm trên | Mobile |
bottom-right |
Góc dưới phải | Alternative |
bottom-center |
Trung tâm dưới | Mobile apps |
3.3. Stacking
- Nhiều toast xếp chồng (stack), toast mới ở trên.
- Max visible: 3–5 toasts. Cũ nhất tự dismiss khi vượt quá.
3.4. Slot Map (Figma ↔ Code)
📎 Source:
slot-manifest.json→toast· Layer: surface
| Figma Slot | data-slot |
CSS Class | Required | Accepts |
|---|---|---|---|---|
| Root | toast |
.surface-toast |
✅ | — |
| Icon | toast-icon |
— | ❌ | severity-icon |
| Content | toast-content |
— | ✅ | text |
| Title | toast-title |
— | ✅ | text |
| Description | toast-description |
— | ❌ | text |
| Action | toast-action |
— | ❌ | button (text variant), close-button |
4. Token Mapping
📦 Token values: Xem
ATOMIC-MAPPING.md— single source of truth cho tất cả actual token values.
| Token | Type | Value | Mô tả |
|---|---|---|---|
max-width |
number | 360 |
Maximum toast width |
padding |
number | {item.padding-default} |
|
radius |
number | {module.radius-default} |
|
gap-icon |
number | {spacing.3} |
Gap between icon and content |
gap-stacking |
number | {spacing.2} |
Vertical gap between stacked toasts |
title-font-size |
number | {font.size.sm} |
|
title-font-weight |
number | {font.weight.semibold} |
|
body-font-size |
number | {font.size.sm} |
|
close-button-size |
number | {min-width.5} |
|
color.default-bg |
color | {base.surface} |
|
color.default-fg |
color | {base.surface-foreground} |
|
color.success-bg |
color | {base.success-muted} |
|
color.success-fg |
color | {base.success-muted-foreground} |
|
color.warning-bg |
color | {base.warning-muted} |
|
color.warning-fg |
color | {base.warning-muted-foreground} |
|
color.destructive-bg |
color | {base.destructive-muted} |
|
color.destructive-fg |
color | {base.destructive-muted-foreground} |
|
color.info-bg |
color | {base.info-muted} |
|
color.info-fg |
color | {base.info-muted-foreground} |
|
color.border |
color | {base.card-border} |
|
color.close-button |
color | {base.muted-foreground} |
|
color.close-hover |
color | {state-layer.hover} |
|
color.progress-bar |
color | {base.primary} |
|
color.disabled-bg |
color | {base.muted} |
Disabled state background |
color.disabled-fg |
color | {base.muted-foreground} |
Disabled state foreground |
elevation |
shadow | {elevation.level-3} |
|
z-index |
number | {z-index.toast} |
|
transition-enter |
string | {duration.normal-2} {easing.emphasized-decelerate} |
Toast slide in |
transition-exit |
string | {duration.normal-1} {easing.emphasized-accelerate} |
Toast slide out |
5. Props & API
typescript
// Toast function API (imperative)
interface ToastOptions {
/** Severity variant */
variant?: 'default' | 'success' | 'warning' | 'destructive' | 'info';
/** Title text */
title: string;
/** Description/body */
description?: string;
/** Auto-dismiss duration (ms). 0 = persistent */
duration?: number; // default: 4000
/** Action button */
action?: {
label: string;
onClick: () => void;
};
/** Show close button */
closable?: boolean; // default: true
/** Show progress bar (auto-dismiss indicator) */
showProgress?: boolean;
}
// Usage: toast({ variant: 'success', title: 'Saved!' })
// Or: toast.success('Saved!')
// Container component
interface ToastContainerProps {
/** Position on screen */
position?: 'top-right' | 'top-center' | 'bottom-right' | 'bottom-center';
/** Max visible toasts */
maxVisible?: number; // default: 5
}
6. Accessibility (a11y)
- Role:
role="status"+aria-live="polite"(info/success).role="alert"+aria-live="assertive"(error/warning). - Screen reader: Nội dung toast phải được announce tự động.
- Close button:
aria-label="Dismiss notification". - Auto-dismiss: Pause timer khi hover hoặc focus (cho user đọc).
- Keyboard:
Tabfocus vào action/close button.Escapedismiss focused toast. - Focus không bị steal: Toast xuất hiện KHÔNG steal focus từ user's current task.
- Reduced motion: Respect
prefers-reduced-motion— giảm/tắt animation.
7. Best Practices & Rules
- Imperative API: Toast dùng function call (
toast.success(...)) — KHÔNG dùng JSX render. - Container singleton: Chỉ 1
<ToastContainer />render ở root app. - Duration: Success 3–4s, Error 5–8s (user cần đọc lỗi), info 4s.
- Persistent error: Error quan trọng NÊN có
duration: 0(phải manual close). - Undo pattern: "Đã xoá. [Hoàn tác]" — action button + 5s timer.
- Stacking: Toast mới xuất hiện phía trên, cũ di chuyển xuống.
- Không Hardcode: Mọi giá trị từ Token.
- Progress bar: Thanh tiến trình hiện thời gian còn lại trước khi auto-dismiss.
- Icon: CHỈ dùng Lucide icon từ
assets/icons/(xemicon.mdmục 10). CẤM dùng text emoji.
8. Example Usage
jsx
{/* Render container once at root */}
<ToastContainer position="top-right" maxVisible={5} />
{/* Imperative calls */}
toast.success('Đã lưu thành công!')
toast({
variant: 'destructive',
title: 'Lỗi kết nối',
description: 'Không thể kết nối đến máy chủ.',
duration: 8000,
action: { label: 'Thử lại', onClick: retry },
})
toast({
variant: 'default',
title: 'Đã xoá giao dịch',
action: { label: 'Hoàn tác', onClick: undo },
duration: 5000,
})
toast.info('Có bản cập nhật mới!')