Prisma
Live Preview

Select Component Generation Skill

Skill này hướng dẫn bạn (AI Agent) tạo component Select / Dropdown — cho phép user chọn một (hoặc nhiều) giá trị từ danh sách predefined.

1. Mục tiêu (Objective)

Tạo component Select hoàn chỉnh, hỗ trợ single/multi select, searchable, grouped options, và tích hợp 100% Design Tokens. Có thể dùng native <select> hoặc custom dropdown tuỳ yêu cầu.

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

Khi nào dùng Select?

  • Chọn từ danh sách có sẵn: quốc gia, loại tài khoản, danh mục
  • Danh sách > 5 options: nếu ≤ 5, cân nhắc Radio (single) hoặc Checkbox (multi)
  • Không cần user tự nhập giá trị mới

Phân biệt với component khác

Tình huống Component đúng Lý do
Chọn 1 từ > 5 options Select Tiết kiệm không gian
Chọn 1 từ ≤ 5 options Radio Group Thấy hết options, chọn nhanh
Chọn nhiều từ > 5 options Select (multi) Dropdown + chips
Chọn nhiều từ ≤ 5 options Checkbox Group Thấy hết, toggle nhanh
Chọn + có thể tự nhập Combobox / Input + Autocomplete Kết hợp input + dropdown
On/Off toggle Switch Chỉ 2 trạng thái

Decision Tree cho AI

text
User cần chọn từ danh sách?
├─ Single selection
│   ├─ > 5 options → Select
│   └─ ≤ 5 options → Radio Group
├─ Multi selection
│   ├─ > 5 options → Select (multi)
│   └─ ≤ 5 options → Checkbox Group
├─ Cần search/filter trong list → Select (searchable) hoặc Combobox
└─ Chỉ 2 trạng thái (on/off) → Switch

3. Ngữ nghĩa & Phân loại (Semantics)

3.1. Default Select (Single)

  • Mục đích: Chọn 1 giá trị từ dropdown.
  • Đặc điểm: Trigger button hiển thị giá trị hiện tại, mở dropdown panel khi click.
  • Tương đồng: Exposed Dropdown Menu (Material 3), Picker (iOS).

3.2. Multi Select

  • Mục đích: Chọn nhiều giá trị, hiển thị dạng chips/tags.
  • Đặc điểm: Checkbox trong mỗi option, chips hiển thị các giá trị đã chọn.

3.3. Searchable Select

  • Mục đích: Danh sách rất dài (> 20 items), cần tìm kiếm nhanh.
  • Đặc điểm: Input field tích hợp trong dropdown để filter.

3.4. Grouped Select

  • Mục đích: Options được phân nhóm theo danh mục.
  • Đặc điểm: <optgroup> hoặc section headers trong custom dropdown.

3.5. States

State Mô tả Token chính
Idle Chưa mở dropdown base.input, base.input-border
Open Dropdown đang hiển thị base.primary (border), base.surface (panel)
Focused Keyboard focus state-layer.focused
Error Validation fail base.destructive (border)
Disabled Không tương tác opacity: base.disabled

3.5. Slot Map (Figma ↔ Code)

📎 Source: slot-manifest.jsonselect · Layer: item

Figma Slot data-slot CSS Class Required Accepts
Root select .select
Label select-label .label text
Trigger select-trigger .select-trigger trigger-button
Value select-value text
Icon select-icon chevron-icon
Content select-content .select-content select-item-group
Item select-item .select-item ✅ (n×) option

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ả
trigger-height.sm number {min-width.8} Small trigger height
trigger-height.md number {min-width.10} Default trigger height
trigger-height.lg number {min-width.12} Large trigger height
trigger-padding-x number {spacing.3} Horizontal padding trigger
trigger-radius number {item.radius} Trigger border radius
panel-radius number {module.radius-default} Dropdown panel radius
panel-max-height number 320 Max height trước scroll (~8 items)
option-padding-x number {item.padding-default} Option horizontal padding
option-padding-y number {item.padding-small} Option vertical padding
option-font-size number {font.size.sm} Option text size
group-header-font-size number {font.size.xs} Group header text size
chevron-size number {min-width.5} Chevron icon size
color.trigger-bg color {base.input} Trigger background
color.trigger-border color {base.input-border} Trigger border
color.trigger-border-open color {base.primary} Border khi dropdown đang mở
color.trigger-text color {base.foreground} Trigger text
color.placeholder color {base.muted-foreground} Placeholder text
color.panel-bg color {base.surface} Dropdown panel background
color.panel-border color {base.card-border} Panel border
color.option-hover color {state-layer.hover} Option hover state
color.option-selected-bg color {base.primary-muted} Selected option bg
color.option-selected-fg color {base.primary-muted-foreground} Selected option text
color.option-text color {base.foreground} Option text
color.group-header color {base.muted-foreground} Group header text
color.check-icon color {base.primary} Check icon color
color.chevron color {base.muted-foreground} Chevron color
color.chip-bg color {base.muted} Multi-select chip bg
color.chip-fg color {base.foreground} Multi-select chip text
color.focus-ring color {focus.ring-color} Focus ring — ref shared/focus
color.disabled-bg color {base.muted} Disabled background
color.disabled-fg color {base.muted-foreground} Disabled foreground
elevation shadow {elevation.level-2} Dropdown panel shadow
z-index number {z-index.dropdown} Dropdown z-index
transition string {duration.fast-2} {easing.standard} Open/close animation
font-weight number {font.weight.medium} Default font weight

5. Props & API

typescript
interface SelectProps {
  /** Single or multi select */
  mode?: 'single' | 'multiple';
  /** Options list */
  options: SelectOption[];
  /** Placeholder khi chưa chọn */
  placeholder?: string;
  /** Label */
  label?: string;
  /** Enable search/filter */
  searchable?: boolean;
  /** Size */
  size?: 'sm' | 'md' | 'lg';
  /** Error message */
  errorMessage?: string;
  /** Helper text */
  helperText?: string;
  /** Disabled */
  disabled?: boolean;
  /** Full width */
  fullWidth?: boolean;
  /** Clearable — cho phép xoá selection */
  clearable?: boolean;
}

interface SelectOption {
  value: string;
  label: string;
  disabled?: boolean;
  group?: string; // Tên nhóm
}

6. Accessibility (a11y)

  • ARIA: Trigger phải có role="combobox", aria-expanded, aria-haspopup="listbox".
  • Listbox: Dropdown panel phải có role="listbox", mỗi option role="option".
  • Keyboard: Enter/Space mở dropdown, Arrow Up/Down di chuyển focus, Escape đóng, Enter chọn.
  • Multi select: Option selected phải có aria-selected="true".
  • Searchable: Input tìm kiếm có aria-autocomplete="list".
  • Label: Liên kết qua aria-labelledby.
  • Focus trap: Focus phải ở trong dropdown khi mở, trả lại trigger khi đóng.

7. Best Practices & Rules

  • Native fallback: Với form đơn giản hoặc mobile, ưu tiên <select> native.
  • Custom dropdown: Khi cần searchable, multi, grouped — dùng custom component.
  • Z-index: Dropdown panel phải có z-index cao hơn surrounding content.
  • Portal: Render dropdown qua Portal để tránh overflow hidden issues.
  • Không Hardcode: Mọi giá trị từ Token.
  • Icon: Dropdown arrow (chevron-down), check icon (check), clear icon (x) CHỈ dùng Lucide icon từ assets/icons/. CẤM dùng text emoji. Xem icon.md mục 10.
  • Max height: Dropdown panel nên có max-height + scroll khi > 8 items.

8. Example Usage

jsx
{/* Basic single */}
<Select
  label="Quốc gia"
  placeholder="Chọn quốc gia"
  options={[
    { value: 'vn', label: 'Việt Nam' },
    { value: 'us', label: 'United States' },
    { value: 'jp', label: 'Japan' },
  ]}
/>

{/* Multi select with search */}
<Select
  mode="multiple"
  searchable
  label="Kỹ năng"
  placeholder="Chọn kỹ năng..."
  options={skills}
/>

{/* Grouped */}
<Select
  label="Sản phẩm"
  options={[
    { value: 'visa', label: 'Visa', group: 'Thẻ quốc tế' },
    { value: 'master', label: 'Mastercard', group: 'Thẻ quốc tế' },
    { value: 'napas', label: 'Napas', group: 'Thẻ nội địa' },
  ]}
/>