Live Preview
Is it accessible?
Yes. It adheres to the WAI-ARIA design pattern for accordions.
Is it styled?
Yes. It uses design tokens from the design system, ensuring consistency.
Is it animated?
Yes. It supports smooth transitions when toggling open/closed states.
--- description: Hướng dẫn Agent tự động tạo UI Component Accordion/Collapsible dựa trên Design Tokens, có ngữ nghĩa chuẩn Material 3 & iOS HIG
Accordion Component Generation Skill
Skill này hướng dẫn bạn (AI Agent) tạo component Accordion / Collapsible — thu gọn và mở rộng nội dung theo section.
1. Mục tiêu (Objective)
Tạo component Accordion hỗ trợ single/multiple expand, smooth animation, và tích hợp 100% Design Tokens.
2. AI Context & Intent (Ngữ cảnh cho AI)
Khi nào dùng Accordion?
- FAQ: Câu hỏi thường gặp, ẩn câu trả lời
- Settings groups: Nhóm cài đặt có thể thu gọn
- Long content: Chia content dài thành sections có thể collapse
- Sidebar navigation: Menu các cấp có thể mở/đóng
Phân biệt với component khác
| Tình huống | Component đúng | Lý do |
|---|---|---|
| Ẩn/hiện content theo section | Accordion | Collapse/expand |
| Chuyển đổi content views | Tabs | Switch, không collapse |
| Show/hide 1 block đơn lẻ | Collapsible (single Accordion) | Simpler |
| Chi tiết item trong list | Expandable Row / Disclosure | Inline expand |
| Popup content | Modal / Popover | Overlay |
Decision Tree cho AI
text
Cần ẩn/hiện nội dung?
├─ Nhiều sections, xếp dọc → Accordion
│ ├─ Chỉ 1 section mở tại 1 thời điểm → type="single"
│ └─ Nhiều sections mở cùng lúc → type="multiple"
├─ 1 block duy nhất ẩn/hiện → Collapsible (single AccordionItem)
├─ Chuyển view khác nhau → Tabs
└─ Content popup → Modal / Popover
3. Ngữ nghĩa & Phân loại (Semantics)
3.1. Behavior Types
| Type | Mô tả |
|---|---|
single |
Chỉ 1 item mở tại 1 thời điểm (mở cái mới → đóng cái cũ) |
multiple |
Nhiều items mở cùng lúc |
3.2. Visual Variants
| Variant | Mô tả |
|---|---|
default |
Border bottom giữa items, nền transparent |
bordered |
Mỗi item có border box riêng, gap giữa items |
filled |
Active item có background highlight |
3.3. Item States
| State | Mô tả | Visual |
|---|---|---|
| Collapsed | Nội dung ẩn | Chevron → phải/xuống |
| Expanded | Nội dung hiện | Chevron → xuống, rotate 180° |
| Disabled | Không thể toggle | Opacity giảm |
3.4. Slot Map (Figma ↔ Code)
📎 Source:
slot-manifest.json→accordion· Layer: card
| Figma Slot | data-slot |
CSS Class | Required | Accepts |
|---|---|---|---|---|
| Root | accordion |
.accordion |
✅ | — |
| Item | accordion-item |
.accordion-item |
✅ (n×) | — |
| Trigger | accordion-trigger |
.accordion-header |
✅ | text + chevron-icon |
| Content | accordion-content |
.accordion-content |
✅ | typography, list, input-group, * |
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ả |
|---|---|---|---|
header-padding-y |
number | {item.padding-default} |
Vertical padding header trigger |
header-padding-x |
number | 0 |
Horizontal padding (0 flush, có padding cho bordered) |
content-padding |
number | {item.padding-default} |
Content area padding |
gap-bordered |
number | {spacing.2} |
Gap giữa items (bordered variant) |
radius |
number | {item.radius} |
Border radius cho bordered variant |
header-font-size |
number | {font.size.sm} |
Header trigger text size |
header-font-weight |
number | {font.weight.medium} |
Header trigger text weight |
content-font-size |
number | {font.size.sm} |
Content body text size |
chevron-size |
number | {min-width.5} |
Chevron icon size |
color.header-background |
color | transparent |
Default variant header bg |
color.header-background-hover |
color | {state-layer.hover} |
Header hover state |
color.header-background-filled |
color | {base.muted} |
Filled variant expanded bg |
color.header-text |
color | {base.foreground} |
Header text color |
color.chevron |
color | {base.muted-foreground} |
Chevron icon color |
color.content-text |
color | {base.foreground} |
Content text color |
color.border |
color | {base.border} |
Separator giữa items |
color.border-bordered |
color | {base.card-border} |
Border cho bordered variant |
color.focus-ring |
color | {focus.ring-color} |
Focus ring — ref shared/focus |
transition |
string | {duration.normal-2} {easing.standard} |
Height expand/collapse animation |
disabled-opacity |
number | {opacity.50} |
Opacity cho disabled items |
5. Props & API
typescript
interface AccordionProps {
/** Behavior type */
type?: 'single' | 'multiple';
/** Active item(s) — controlled */
value?: string | string[];
/** Default open item(s) — uncontrolled */
defaultValue?: string | string[];
/** Visual variant */
variant?: 'default' | 'bordered' | 'filled';
/** Collapsible — cho phép đóng tất cả (type=single) */
collapsible?: boolean;
/** onChange callback */
onChange?: (value: string | string[]) => void;
children: ReactNode;
}
interface AccordionItemProps {
/** Unique value */
value: string;
/** Header trigger text */
title: string;
/** Sub-title / description trong header */
subtitle?: string;
/** Disabled */
disabled?: boolean;
/** Custom trigger icon (thay thế chevron) */
icon?: ReactNode;
/** Content */
children: ReactNode;
}
6. Accessibility (a11y)
- Trigger:
<button>hoặc<h*>với<button>bên trong.aria-expanded="true"/"false". - Content:
role="region",aria-labelledby="[trigger-id]". - Keyboard:
Enter/Spacetoggle.Arrow Up/Downdi chuyển giữa triggers.Home/End→ first/last. - Heading: Trigger nên wrap trong
<h*>tag phù hợp hierarchy trang. - Disabled:
aria-disabled="true", skip khi keyboard navigate.
7. Best Practices & Rules
- Animation: Smooth height transition (CSS
max-heighthoặc JSheight). Respectprefers-reduced-motion. - Overflow: Content bên trong phải handle overflow đúng (không bị cắt khi animated).
- Không Hardcode: Mọi giá trị từ Token.
- Icon: Chevron expand/collapse (
chevron-down) CHỈ dùng Lucide icon từassets/icons/. CẤM dùng text emoji. Xemicon.mdmục 10. - Default open: FAQ thường nên mở item đầu tiên mặc định.
8. Example Usage
jsx
{/* FAQ accordion */}
<Accordion type="single" collapsible defaultValue="q1">
<AccordionItem value="q1" title="Làm sao để liên kết thẻ?">
Vào Cài đặt → Thẻ liên kết → Thêm thẻ mới...
</AccordionItem>
<AccordionItem value="q2" title="Phí giao dịch là bao nhiêu?">
Miễn phí cho giao dịch dưới 500.000đ...
</AccordionItem>
<AccordionItem value="q3" title="Làm sao để đổi mật khẩu?">
Vào Cài đặt → Bảo mật → Đổi mật khẩu...
</AccordionItem>
</Accordion>
{/* Settings, multiple open */}
<Accordion type="multiple" variant="bordered">
<AccordionItem value="general" title="Cài đặt chung">...</AccordionItem>
<AccordionItem value="security" title="Bảo mật">...</AccordionItem>
<AccordionItem value="notifications" title="Thông báo">...</AccordionItem>
</Accordion>