Prisma

🔬 Phân tích UX: Vị trí cụm nút (Action Group Placement)

Ngày: 2026-03-12 | Phạm vi: Web + App | Mức độ: 🔴 Critical (UX consistency)


1. Vấn đề phát hiện

1.1 Web: Cụm nút lúc bên trái, lúc bên phải

Nguyên nhân gốc: Có 3 CSS class khác nhau cho footer/action group, mỗi class dùng alignment khác nhau:

CSS Class justify-content Alignment Đang dùng bởi
.slot-footer flex-end ▶ Phải Slot system (chuẩn)
.slot-footer-clean flex-end ▶ Phải Slot system (no border)
.slot-footer-between space-between ◀▶ Hai bên Slot system (variant)
.drawer-preview-footer flex-end ▶ Phải Dialog/Modal/Drawer previews
.card-footer (không set) Trái (default) Card previews

⚠️ .card-footer KHÔNG có justify-content → mặc định flex-start (trái), trong khi toàn bộ overlay components (dialog, modal, drawer) đều canh phải (flex-end).

Kết quả: User nhìn Card thấy nút bên trái, mở Dialog/Modal thấy nút bên phải → mất consistency, vi phạm NNG H4 (Consistency & Standards).

1.2 App: Chưa có layout spec cho cụm nút

Hiện tại, DS chỉ có:

  • Button pairing rules (§4.5) — variant ghép đôi (primary ↔ outline)
  • Button size rules (BS-1 → BS-5) — quy tắc chọn size
  • KHÔNG CÓ quy tắc về vị trí / alignment của cụm nút
  • KHÔNG CÓ utility class .action-group hay .action-bar cho app context

2. Phân tích hệ thống tham chiếu

2.1 So sánh Web vs App

Yếu tố Web Desktop App Mobile
Chiều rộng viewport Rộng (1024px+) → buttons nhỏ so với container → cần anchor (phải) Hẹp (320-414px) → buttons gần full-width → center tự nhiên
Thao tác tay Chuột → không giới hạn vùng Ngón cái → vùng trung tâm thoải mái nhất (thumb zone)
Visual weight Nhiều content → buttons cần "neo" vào góc phải Ít content → center tạo cân bằng thị giác
Pattern phổ biến shadcn/MD3 web → flex-end iOS Alert, Bottom Sheet, Banking CTA → center

2.2 Reference Systems

Material Design 3:

  • Web Dialog/AlertDialog → trailing (phải)
  • Mobile Bottom Sheet → center, full-width buttons
  • Card actions → thường trailing

Apple HIG:

  • Alert (iOS) → center (stacked full-width)
  • Sheet (macOS) → trailing
  • Navigation Bar → leading/trailing slots

shadcn/ui:

  • Dialog / AlertDialog → flex-end (phải)
  • Card → flex (no justify — left default)

Banking apps (VCB, Momo, ZaloPay): CTA luôn center full-width.


3. Đề xuất: Hệ thống Action Group Placement

3.1 Nguyên tắc cốt lõi — Platform-Aware Alignment

Platform Quy tắc alignment Lý do
Web (desktop) Trailing (flex-end) Z-pattern scan, Fitts's Law, MD3/shadcn consensus
App (mobile) Center (full-width, centered) Thumb zone, visual balance, iOS/Android native pattern

Đây là sự khác biệt có chủ đích dựa trên platform context, không phải inconsistency.

3.2 Bảng quy tắc — AG Rules

# Rule Web App Source
AG-1 Web trailing — Cụm nút trên web desktop mặc định justify-content: flex-end MD3, shadcn, Z-pattern
AG-2 App center — Cụm nút trên mobile app mặc định center, full-width HIG, Thumb Zone Law
AG-3 Button order — Cancel/secondary trước (trái), Confirm/primary sau (phải) MD3, shadcn
AG-4 Gap chuẩn — Inline: gap: var(--spacing-2) (8px). Stacked: gap: var(--spacing-3) (12px) 4px grid (S2)
AG-5 Mobile CTA stacked — Mobile (≤768px), ≥2 buttons → stack vertical, full-width, CTA trên HIG, BS-4
AG-6 Between variantslot-footer-between khi cần metadata trái + action phải MD3 Card pattern
AG-7 Sticky action bar — CTA quan trọng (checkout, submit) → sticky bottom, safe-area padding iOS Safe Area

3.3 CSS Implementation

css
/* ─── Action Group — Web: trailing, responsive stack ─── */
.action-group {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    gap: var(--spacing-2);
    flex-wrap: wrap;
}

/* Mobile: center, full-width stacked */
@media (max-width: 768px) {
    .action-group--responsive {
        flex-direction: column-reverse;
        align-items: stretch;
    }
    .action-group--responsive > .btn {
        width: 100%;
        justify-content: center;
    }
}

3.4 Fix List

Fix File Chi tiết
🔴 components.css .card-footer thêm justify-content: flex-end;
🟡 components.css Thêm .action-group + responsive variant
🟡 button.md Thêm §4.8 — Action Group Placement Rules
🟡 UX skill domains-nav-layout-component.md Thêm §5.5 AG rules

3.5 Sơ đồ visual

text
WEB — Overlay/Card: Trailing (flex-end)
┌────────────────────────────────┐
│  Title                    [✕]  │
│  Description text...           │
│           [Cancel] [Confirm]   │ ← flex-end ✅
└────────────────────────────────┘

APP — Mobile: Center, stacked full-width
┌────────────────────────────────┐
│  Title                         │
│  Content...                    │
│  ┌──────────────────────────┐  │
│  │       Xác nhận           │  │ ← full-width center ✅
│  └──────────────────────────┘  │
│  ┌──────────────────────────┐  │
│  │         Huỷ              │  │ ← full-width center ✅
│  └──────────────────────────┘  │
└────────────────────────────────┘