Prisma
Live Preview
Variants
Sizes
States
With Icon

Button Component Generation Skill

Skill này hướng dẫn bạn (AI Agent) đóng vai trò là một UI Engineer chuyên trách việc tự động tạo mã nguồn cho component Button. Bạn sẽ sử dụng Design Tokens, thông tin từ Figma MCP Server và áp dụng đúng ngữ nghĩa của các loại Button theo tiêu chuẩn thiết kế hiện đại.

1. Mục tiêu (Objective)

Tạo ra một file component Button (vd: Button.tsx, Button.vue, hoặc HTML/CSS) hoàn chỉnh, tái sử dụng được, tuân thủ 100% design system thông qua các Design Tokens có sẵn trong thư mục Tokens/. Đặc biệt, phải đảm bảo Component áp dụng đúng ngữ nghĩa và phân loại để User có trải nghiệm nhất quán.

2. Ngữ nghĩa và Phân loại Button (Semantics - Dựa trên Material 3 & iOS HIG)

Khi thiết kế hoặc tạo Component, phải chia Button thành các variant rõ ràng và hiểu ngữ nghĩa sử dụng của từng loại để dùng đúng lúc, đúng chỗ:

2.1. Primary / Filled Button (High Emphasis)

  • Mục đích: Dùng cho hành động chính, quan trọng nhất trên màn hình (như "Save", "Submit", "Confirm"). Thông thường mỗi màn hình chỉ nên có một (hoặc rất ít) Primary Button.
  • Đặc điểm: Màu nền đậm (Solid Background), chữ tương phản cao. Thể hiện sự tập trung cao nhất.
  • Tương đồng: Filled Button (Material 3), Primary / Filled Button (iOS).

2.2. Secondary / Tonal / Tinted Button (Medium Emphasis)

  • Mục đích: Dùng cho các hành động phụ trợ quan trọng hoặc các tuỳ chọn thay thế khi không muốn lấn át hành động chính.
  • Đặc điểm: Màu nền nhạt (thường là màu Primary giảm Opacity hoặc màu Neutral sáng), chữ hoặc icon đồng màu với Action Color.
  • Tương đồng: Filled Tonal Button (Material 3), Tinted / Gray Button (iOS).

2.3. Outlined Button (Medium-Low Emphasis)

  • Mục đích: Dùng cho các hành động phụ, mang tính độc lập hoặc là hành động đối ứng bắt buộc khi đặt cạnh Primary hoặc Destructive Button (vd: "Cancel" cạnh "Submit", "Cancel" cạnh "Delete").
  • Đặc điểm: Nền trong suốt (Transparent), có đường viền (Border) màu Primary hoặc Neutral.
  • Tương đồng: Outlined Button (Material 3).
  • ⚠️ Rule: Xem thêm mục 4.5 — Button Pairing Rules.

2.4. Ghost / Text / Plain Button (Low Emphasis)

  • Mục đích: Dùng cho các hành động ít quan trọng rải rác trên giao diện (vd: "Learn more", "Skip", "Reply" trong bình luận) hoặc nằm ở thanh công cụ.
  • Đặc điểm: Chỉ có text hoặc icon, không có nền hay viền mặc định. Hình hộp chỉ hiện ra khi Hover / Tương tác.
  • Tương đồng: Text Button (Material 3), Plain Button (iOS).

2.5. Destructive Button (Negative Action)

  • Mục đích: Cảnh báo user về một hành động không thể hoàn tác, gây phá hủy dữ liệu (vd: "Delete", "Remove").
  • Đặc điểm: Thường sử dụng tông màu Khẩn cấp/Lỗi (Red/Error) cho Background hoặc Text. Có đầy đủ các trạng thái (Filled, Outlined, Text).

3. Các bước thực hiện

Bước 1: Thu thập Context từ Figma

  1. Yêu cầu User cung cấp Figma Node ID của Button component.
  2. Chạy mcp_figma-dev-mode-mcp-server_get_metadata với Node ID để phân tích cấu trúc layer (thường gồm: Text layer, Icon trái/phải, Background, Border).
  3. Chạy mcp_figma-dev-mode-mcp-server_get_design_context để lấy các thông số cơ bản (spacing, color, radius) của trạng thái mặc định.
  4. Chạy mcp_figma-dev-mode-mcp-server_get_variable_defs để trích xuất các Token/Variable đang được gán.

Bước 2: Mapping Button Tokens

📦 Atomic Mapping: Xem ATOMIC-MAPPING.md → mục button — mappping trực tiếp từ semantic tokens. KHÔNG dùng component token JSON layer (đã deprecated).

Đối chiếu các thuộc tính từ Figma sang Design Tokens (KHÔNG dùng mã hex cứng/giá trị tĩnh). CSS dùng trực tiếp semantic tokens:

  • Sizing: --size-min-width-*, --spacing-* (theo sm/md/lg)
  • Colors: --primary, --primary-foreground, --destructive, --state-layer-hover etc.
  • Typography: --font-size-*, --font-weight-*
  • Border: --comp-radius (từ density tier), --border
  • Motion: --motion-hover

Bước 3: Xử lý State Layers (Trạng thái tương tác)

Button BẮT BUỘC phải quy định rõ cách xử lý các trạng thái tương tác:

  • Hover: Sử dụng layer phủ màu hoặc thay đổi Token từ Tokens/themes/state-layers.tokens.json (vd: hover-overlay, darken, lighten).
  • Focus: Thêm viền focus ring (focus-visible) dành cho thao tác bàn phím, đảm bảo Accessibility.
  • Disabled: Giảm Opacity (thường khoảng opacity-38 đến opacity-50) và vô hiệu hóa con trỏ (cursor-not-allowed). KHÔNG có hiệu ứng Hover khi Disabled.
  • Active / Pressed: Đổi token nền thành màu tối hơn hoặc sử dụng pressed-overlay.

Bước 4: Xây dựng Component Code

Cấu trúc Component phải định nghĩa các Props bao quát các phân loại ở mục 2:

  • variant: primary (Filled) | secondary (Tonal) | outline | ghost (Text) | destructive
  • size: sm | md | lg
  • disabled: boolean
  • leftIcon / rightIcon: Node/Component Icon
  • isLoading (Optional): Trạng thái đang tải, hiển thị Spinner/Loader và tự động làm mờ text, vô hiệu hoá thao tác.

3.1. Slot Map (Figma ↔ Code)

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

Figma Slot data-slot CSS Class Required Accepts
Root button .btn
Icon button-icon icon (leading or trailing)
Label button-label text

4. Best Practices & Rules

  • Semantic HTML: Phải Render bằng thẻ <button type="button">. Nếu button được bọc bên trong form, chỉ dùng type="submit" khi có ý định submit. Dùng thẻ <a> nếu có thuộc tính href (hành động điều hướng).
  • Accessibility (a11y): Nút chỉ chứa Icon BẮT BUỘC phải có aria-label.
  • Hỗ trợ Hệ điều hành (iOS/Android): Touch target (Vùng bấm) phải đạt tối thiểu 44x44px (iOS) hoặc 48x48px (Material).
  • Dark Mode: Sử dụng CSS Variables tĩnh cho Token hoặc cấu trúc class hỗ trợ tự động (VD: Tailwind dark:bg-primary-dark).
  • Không Hardcode: Toàn bộ UI phải mapping từ Token, không tự ý chèn màu thuần hay margin/padding thuần tuỳ tiện.
  • Icon: Button có leftIcon/rightIcon CHỈ dùng Lucide icon từ assets/icons/. CẤM dùng text emoji hoặc icon từ library khác. Xem icon.md mục 10.

4.9. Mobile App Rules (B8-B10, B13)

Rule ID Requirement
BG-1 B9 Ghost hover = background: transparent. Mobile không có cursor hover — state-layer-hover gây visual noise.
BI-1 B10 .btn--icon PHẢI dùng border-radius: var(--comp-radius-capsule) (fully round 9999px). --comp-radius mobile = 8px trông quá vuông cho icon button.
BT-1 B13 transition: all CẤM. Phải list explicit properties: background, color, filter, transform, opacity. all gây glitch (dark line artifact) do animate border/outline/text-decoration.

4.5. Button Pairing Rules (Quy tắc ghép đôi Button)

Khi một nhóm hành động có 2 button cạnh nhau (Action Group / Dialog Footer), phải tuân thủ quy tắc ghép đôi sau:

Main Action (CTA) Counter Action (Đối ứng) Ví dụ
primary (Filled) outline Submit ↔ Cancel
destructive (Filled) outline Delete Account ↔ Cancel

⚠️ BẮT BUỘC: Khi main action là primary hoặc destructive, button đối ứng PHẢI dùng variant outline. KHÔNG được dùng ghost hoặc secondary làm đối ứng.

Lý do:

  • Outline tạo sự phân cấp rõ ràng (Medium-Low vs High Emphasis) mà vẫn giữ được độ nhận diện nhờ border.
  • Ghost quá nhẹ, dễ bị bỏ sót khi đặt cạnh button filled → gây mất cân bằng thị giác.
  • Secondary (Tonal) có emphasis quá gần với Primary → confusing, user khó phân biệt hành động chính / phụ.

Ví dụ đúng ✅:

html
<!-- Dialog: Xóa tài khoản -->
<div class="dialog-actions">
  <button class="btn btn-outline">Cancel</button>
  <button class="btn btn-destructive">Delete Account</button>
</div>

<!-- Dialog: Xác nhận hành động -->
<div class="dialog-actions">
  <button class="btn btn-outline">Cancel</button>
  <button class="btn btn-primary">Confirm</button>
</div>

Ví dụ sai ❌:

html
<!-- SAI: ghost quá nhẹ, mất cân bằng -->
<button class="btn btn-ghost">Cancel</button>
<button class="btn btn-destructive">Delete</button>

<!-- SAI: secondary quá gần emphasis với primary -->
<button class="btn btn-secondary">Cancel</button>
<button class="btn btn-primary">Submit</button>

Ngoại lệ: Khi có ≥ 3 button trong cùng một nhóm, có thể kết hợp outline + ghost cho các hành động phụ. Nhưng hành động đối ứng trực tiếp với CTA vẫn PHẢI là outline.

4.6. Full-Width Modifier (.btn--block)

Reference: MD3 Extended FAB width pattern, Apple HIG full-width CTA

Khi button cần chiếm toàn bộ chiều ngang container (mobile form CTAs, checkout, login):

css
.btn--block {
  width: 100%;
  display: flex;
  justify-content: center;
}
Rule Detail
Variants allowed primary, destructive only — secondary/ghost quá nhẹ cho full-width
Use case Mobile form submit, login, checkout CTA, bottom action bar
Stacking Khi 2 full-width buttons stack vertical, dùng gap: var(--spacing-3)
Responsive On desktop (≥768px), nên revert to auto-width trừ khi trong modal
html
<!-- Mobile login CTA -->
<button class="btn btn-primary btn--block btn--lg">Đăng nhập</button>

<!-- Stacked pair -->
<div class="btn-stack" style="display: flex; flex-direction: column; gap: var(--spacing-3);">
  <button class="btn btn-primary btn--block">Thanh toán tiền mặt</button>
  <button class="btn btn-outline btn--block">Thanh toán QR</button>
</div>

4.7. Button Size Rules (Quy tắc chọn Size)

Reference: MD3 density system, Apple HIG touch targets (44×44px), WCAG 2.5.8 Target Size (24×24px AA)

Default size: md (Medium). Khi không có lý do cụ thể để dùng size khác, LUÔN dùng md.

Size Specs
Size Class min-height Padding Font Touch target
sm .btn-sm 32px 4px 12px 12px (xs) ✅ WCAG AA (≥24px)
md .btn (default) 40px 8px 16px 14px (sm) ✅ WCAG AA + MD3
lg .btn-lg 48px 12px 24px 16px (base) ✅ iOS HIG (≥44px)
Context Guide — Khi nào dùng Size nào?
Context Size Lý do
Forms / Dialog / Standard UI md Cân bằng visual weight, đủ touch target (40px ≥ WCAG AA 24px)
Primary action / CTA lg Tăng visual prominence, thu hút hành động chính
Mobile primary button lg Đạt iOS HIG 44px touch target, dễ thao tác ngón cái
Secondary actions sm / md Giảm emphasis so với CTA, không lấn át hành động chính
Toolbar / dense UI sm Tiết kiệm diện tích, phù hợp thao tác liên tục
Icon-only button md Giữ min 40×40px cho accessibility
Rules

Rule BS-1 — Default = Medium Khi tạo button mà KHÔNG xác định rõ context, PHẢI dùng .btn (md). CẤM dùng .btn-lg cho mọi button.

Rule BS-2 — CTA hierarchy Trong cùng một view, chỉ cho phép TỐI ĐA 1-2 button .btn-lg. Nếu nhiều hơn → mất hierarchy.

Rule BS-3 — Size pairing Khi ghép 2 button cạnh nhau (action group), cả 2 PHẢI cùng size. KHÔNG mix .btn-sm + .btn-lg.

Rule BS-4 — Mobile CTA Trên mobile (≤768px), primary CTA nên dùng .btn-lg.btn--block để tối ưu touch target + visual weight.

Rule BS-5 — Form consistency Trong form, tất cả button (Submit, Cancel, Reset) PHẢI dùng cùng size (khuyến nghị md).

Ví dụ đúng ✅
html
<!-- Standard form — all buttons md (default) -->
<div class="dialog-actions">
  <button class="btn btn-outline">Cancel</button>
  <button class="btn btn-primary">Submit</button>
</div>

<!-- Landing page CTA — lg for emphasis -->
<button class="btn btn-primary btn-lg">Get Started</button>

<!-- Mobile CTA — lg + block -->
<button class="btn btn-primary btn-lg btn--block">Đăng nhập</button>

<!-- Toolbar — sm for density -->
<div class="toolbar">
  <button class="btn btn-ghost btn-sm">Copy</button>
  <button class="btn btn-ghost btn-sm">Paste</button>
</div>
Ví dụ sai ❌
html
<!-- SAI: btn-lg cho mọi button → mất hierarchy (BS-1, BS-2) -->
<button class="btn btn-primary btn-lg">Save</button>
<button class="btn btn-outline btn-lg">Cancel</button>
<button class="btn btn-ghost btn-lg">Reset</button>

<!-- SAI: mix size trong cùng action group (BS-3) -->
<div class="dialog-actions">
  <button class="btn btn-outline btn-sm">Cancel</button>
  <button class="btn btn-primary btn-lg">Submit</button>
</div>

4.8. Action Group Placement Rules (Quy tắc vị trí cụm nút)

Reference: MD3 Dialog/Card, Apple HIG Alert/Sheet, shadcn/ui Dialog, NNG Z-Pattern, Thumb Zone Law

Research: knowledge/research/button-group-placement-analysis.md

Core principle — Platform-Aware Alignment:

Platform Default Alignment Lý do
Web (desktop) flex-end (trailing/phải) Z-pattern scan, Fitts's Law, MD3/shadcn consensus
App (mobile) center (full-width) Thumb zone, visual balance, iOS/Android native pattern
AG Rules
# Rule Web App
AG-1 Web trailingjustify-content: flex-end
AG-2 App center — center, full-width buttons
AG-3 Button order — Cancel trước (trái/trên), Confirm sau (phải/dưới)
AG-4 Gap — Inline: var(--spacing-2), Stacked: var(--spacing-3)
AG-5 Mobile stacked — ≥2 buttons → stack vertical, full-width, CTA trên
AG-6 Between — Metadata trái + action phải → .slot-footer-between
AG-7 Sticky action bar — CTA quan trọng → sticky bottom, safe-area

CSS class: .action-group (web trailing), .action-group--responsive (mobile stack)

Ví dụ đúng ✅
html
<!-- Web: trailing alignment (AG-1, AG-3) -->
<div class="action-group">
  <button class="btn btn-outline">Cancel</button>
  <button class="btn btn-primary">Submit</button>
</div>

<!-- Web: responsive — trailing on desktop, stacked on mobile (AG-5) -->
<div class="action-group action-group--responsive">
  <button class="btn btn-outline">Cancel</button>
  <button class="btn btn-primary">Submit</button>
</div>

<!-- Between: metadata left, action right (AG-6) -->
<div class="slot-footer-between">
  <span>3 items selected</span>
  <button class="btn btn-destructive">Delete</button>
</div>

5. Output kết quả

  • Code hoàn chỉnh của Button component (chia ra variants theo chuẩn).
  • Mô tả các thay đổi, giải thích cách mapping token.
  • Ghi chú cách gọi Component (Example Usage).