Prisma

# Slot System — Hướng dẫn tổ chức & sử dụng

Đối tượng: Designer (Figma) + Developer (CSS/HTML) Source of truth: knowledge/slot-manifest.json — 42 components Trạng thái: ✅ Production-ready — 40/42 components đã mapping


1. Slot là gì?

Slot là vùng nội dung linh hoạt bên trong component. Thay vì hardcode nội dung, component định nghĩa các "ổ cắm" (slot) — designer/developer chỉ cần kéo/đặt nội dung vào đúng slot.

Ví dụ: Card có 4 slots

text
┌─────────────────────────┐
│ slot: header             │ ← Title + Action button
│─────────────────────────│
│ slot: content            │ ← Nội dung chính (text, image, list...)
│                          │
│─────────────────────────│
│ slot: footer             │ ← Buttons, links
└─────────────────────────┘

Tại sao dùng Slot?

Vấn đề KHÔNG có slot Giải pháp CÓ slot
Designer phải detach component để thay nội dung Kéo thả vào slot, không detach
Developer tự đặt tên class → không thống nhất data-slot attribute — tên chuẩn hóa
Code Connect không mapping được nội dung Figma Dev Mode hiển thị đúng slot → code

2. Quy ước đặt tên (Convention)

2.1. Ba lớp naming

Mỗi slot element có 3 lớp thông tin — mỗi lớp phục vụ mục đích khác nhau:

Lớp Pattern Mục đích Ví dụ
Structural .slot-{region} Layout (padding, flex, border) .slot-header, .slot-body, .slot-footer
Component .{comp}__{element} Styling riêng component .card__title, .appbar__actions
Identity data-slot="{name}" Figma↔Code mapping — LUÔN CÓ data-slot="card-header"

⚠️ Quy tắc cốt lõi: data-slot attribute LUÔN phải có trên mọi slot element. Đây là cầu nối giữa Figma và code.

2.2. Structural Slots — Chỉ có 3

Dùng chung (reusable) cho mọi container-level components:

Slot CSS Class Biến thể Dùng cho
Header .slot-header .slot-header-clean (no border) Title + actions
Body .slot-body .slot-body-flush (no padding), .slot-body-compact Main content
Footer .slot-footer .slot-footer-between (space-between) Actions, pagination

Components dùng structural slots: card, modal, dialog, bottom-sheet, drawer, sidebar, popover, table, tabs

2.3. data-slot Grammar — 4 quy tắc

Quy tắc Mô tả Đúng ✅ Sai ❌
R1 Root = tên component data-slot="card"
R2 Child = {parent}-{child} data-slot="card-header"
R3 Tối đa 2 cấp (giữ flat) card-title card-header-title (3 cấp)
R4 Chỉ dùng 14 suffix chuẩn Xem bảng bên dưới card-custom-area

2.4. Bảng 14 Suffix chuẩn (R4)

Đây là toàn bộ từ vựng cho phần -child trong data-slot:

Suffix Ngữ nghĩa Dùng cho
-header Vùng trên Title + actions container
-content / -body Vùng chính Primary content area
-footer Vùng dưới Actions, pagination
-title Heading text h2/h3 bên trong header
-description Text phụ p/span bên dưới title
-action Interactive Buttons, links
-trigger Khởi tạo tương tác Button mở popover/select
-item Child lặp lại List items, menu items, tabs
-icon Graphic SVG icon slot
-leading Bên trái Trước content
-trailing Bên phải Sau content
-close Đóng/dismiss Close X button
-overlay Backdrop Modal/sheet backdrop
-separator Phân cách Giữa các items

3. Decision Tree — Chọn pattern nào?

text
Component có content areas?
  │
  ├─ Container-level (card, modal, sheet, drawer)?
  │   ├─ Header/Body/Footer → dùng .slot-* structural class
  │   ├─ Inner elements → dùng BEM .__element
  │   └─ PHẢI có data-slot trên CẢ HAI
  │
  ├─ Inline-level (button, badge, chip)?
  │   ├─ KHÔNG dùng .slot-* (quá đơn giản)
  │   ├─ Inner elements → optional BEM
  │   └─ data-slot chỉ trên root + named parts
  │
  └─ Navigation (tabs, breadcrumb, pagination)?
      ├─ Group container → data-slot on root
      ├─ Items → data-slot="{component}-item"
      └─ KHÔNG dùng .slot-* (không có header/body/footer)

4. Ví dụ thực tế

4.1. Container component — Card

html
<article class="card" data-slot="card">
  <div class="slot-header" data-slot="card-header">
    <h3 class="card__title" data-slot="card-title">Tiêu đề</h3>
    <p data-slot="card-description">Mô tả phụ</p>
    <button data-slot="card-action">⋯</button>
  </div>
  <div class="slot-body" data-slot="card-content">
    <!-- Nội dung chính -->
  </div>
  <div class="slot-footer" data-slot="card-footer">
    <button class="btn btn--outline">Huỷ</button>
    <button class="btn btn--primary">Xác nhận</button>
  </div>
</article>

Giải thích từng lớp:

  • .slot-header → CSS structural class (padding, flex layout)
  • data-slot="card-header" → Figma identity → Code Connect mapping
  • .card__title → BEM class cho styling riêng card title

4.2. Inline component — Button

html
<button class="btn btn--primary" data-slot="button">
  <svg data-slot="button-icon"><use href="#ic-plus"/></svg>
  <span data-slot="button-label">Thêm mới</span>
</button>

Lưu ý: Button/Badge/chip KHÔNG dùng .slot-* structural class — chỉ cần data-slot.

4.3. Navigation — Bottom Nav

html
<nav class="navigation-bar" data-slot="navigation-bar">
  <button class="navigation-bar__item active" data-slot="navigation-bar-item">
    <svg data-slot="navigation-bar-icon"><use href="#ic-home"/></svg>
    <span data-slot="navigation-bar-label">Trang chủ</span>
  </button>
  <button class="navigation-bar__item" data-slot="navigation-bar-item">
    <svg data-slot="navigation-bar-icon"><use href="#ic-wallet"/></svg>
    <span data-slot="navigation-bar-label">Ví</span>
  </button>
</nav>

4.4. List component — List Group

html
<section class="card-listgroup" data-slot="list">
  <div class="card-listgroup__header" data-slot="list-header">
    Danh sách
  </div>
  <button class="card-listgroup__item" data-slot="list-item">
    <span data-slot="list-leading">👤</span>
    <span data-slot="list-content">
      <span data-slot="list-title">Nguyễn Văn A</span>
      <span data-slot="list-subtitle">Admin</span>
    </span>
    <span data-slot="list-trailing">›</span>
  </button>
</section>

5. Slot Map — Bảng tham chiếu theo component

Mỗi component spec (.md) đã có section ## Slot Map (Figma ↔ Code). Bảng dưới tóm tắt các component chính:

5.1. Container Components

Component Slots Structural?
Card header, content, footer, title, description, action, image .slot-*
Modal header, content, footer, title, description, close .slot-*
Dialog icon, title, description, actions ❌ (compact)
Bottom Sheet header, content, footer, handle .slot-*
Drawer header, content, footer, title, close .slot-*

5.2. Form Components

Component Slots
Input label, leading, trailing, helper
Select label, trigger, value, content, items
Textarea label, field, helper
Checkbox indicator, label, description
Radio indicator, label, description
Switch thumb, label

5.3. Navigation Components

Component Slots
App Bar leading, title, actions
Bottom Nav icon, label (per item)
Tabs list, triggers, content
Breadcrumb items, separator
Pagination prev, next, items

5.4. Feedback Components

Component Slots
Toast icon, title, description, action
Alert icon, title, description, action

5.5. Atomic Components

Component Slots
Button icon, label
Badge icon, label
Avatar image, fallback, badge
chip icon, label, remove
Empty State illustration, title, description, action

6. TypeScript API — Typed Slots

File design-system/code-connect/slot-api.d.ts cung cấp typed interfaces cho mọi component:

typescript
import type { CardSlots, ModalSlots } from './slot-api';

// Cách dùng typed slots
const cardConfig: CardSlots = {
  header: titleElement,              // data-slot="card-header"
  body: contentElement,              // data-slot="card-content"  ← required
  footer: actionButtons,            // data-slot="card-footer"
  title: "Tiêu đề card",           // data-slot="card-title"
  action: moreButton,              // data-slot="card-action"
};

Required vs Optional slots

  • Required (không có ?): Component BẮT BUỘC phải có slot này
  • Optional (có ?): Có thể bỏ qua
  • Array ([]): Slot lặp lại (list items, tabs)

7. Figma Code Connect

Khi designer inspect component trong Figma Dev Mode, Code Connect sẽ hiện code template với đúng slot mapping:

typescript
// Tự động hiện trong Figma Dev Mode
figma.connect("https://figma.com/...", {
  props: {
    header: figma.slot("Header"),
    content: figma.slot("Content"),
    footer: figma.slot("Footer"),
  },
  example: (props) => `
    <article class="card" data-slot="card">
      <div class="slot-header" data-slot="card-header">${props.header}</div>
      <div class="slot-body" data-slot="card-content">${props.content}</div>
      <div class="slot-footer" data-slot="card-footer">${props.footer}</div>
    </article>
  `,
});

Preferred Instances — Gợi ý cho Designer

File preferred-instances.json chứa gợi ý component cho từng slot:

json
{
  "card-footer": {
    "preferred": ["Button/Primary/md + Button/Outline/md"],
    "description": "Action button group"
  }
}

Designer sẽ thấy gợi ý thay vì tự đoán nên dùng component gì.


8. Anti-patterns — Những lỗi thường gặp

❌ Sai ✅ Đúng Lý do
.card-header (ambiguous) .slot-header + data-slot="card-header" Tách layout class vs identity
data-slot="card-header-title" data-slot="card-title" R3: tối đa 2 cấp
data-slot="my-custom-slot" Dùng 14 suffix chuẩn (R4) Chỉ 14 suffix được phép
.slot-icon .card__icon .slot-* chỉ cho 3 structural regions
HTML không có data-slot Luôn thêm data-slot Figma Code Connect cần attribute
Tự nghĩ slot name mới Check slot-manifest.json trước Single source of truth
Chỉ thêm Slot Map, quên Code Connect Cập nhật cả 5 files Đồng bộ toàn bộ hệ thống

9. Checklist — Khi tạo/sửa component

text
☐ Component .md có ## Slot Map (Figma ↔ Code) section?
☐ Slot names match slot-manifest.json?
☐ CSS class theo convention? (structural .slot-* vs BEM __)
☐ HTML có data-slot attributes?
☐ code-connect.config.json có entry?
☐ slot-api.d.ts có typed interface?
☐ preferred-instances.json có mapping?
☐ Slot names chỉ dùng 14 suffix chuẩn (R4)?

Files cần cập nhật khi tạo component mới

# File Hành động
1 knowledge/slot-manifest.json Thêm slot definitions (nếu mới)
2 design-system/components md/{name}.md Thêm ## Slot Map section
3 design-system/code-connect/code-connect.config.json Thêm component entry
4 design-system/code-connect/slot-api.d.ts Thêm {Name}Slots interface
5 design-system/code-connect/preferred-instances.json Thêm slot → instance mapping

10. Kiến trúc File

text
knowledge/
├── slot-manifest.json              ← 🔒 Source of truth (42 components)
└── slot-convention.md              ← 📏 Quy ước CSS naming (chi tiết)

design-system/code-connect/
├── code-connect.config.json        ← 🔗 40 components mapping
├── generate-code-connect.js        ← ⚙️ Generator → .figma.ts
├── slot-api.d.ts                   ← 📐 TypeScript interfaces
├── preferred-instances.json        ← 🎯 Gợi ý Figma instances
├── README.md                       ← 📖 Hướng dẫn setup
└── generated/                      ← 📦 40 .figma.ts (auto-generated)

design-system/components md/
└── *.md                            ← 📝 40 files có ## Slot Map section

11. Thống kê

Metric Giá trị
Components có Slot Map 40 / 42
Components trong Code Connect 40
Typed interfaces 40
Preferred instance mappings 40 components
CSS structural classes 3 (header, body, footer)
Approved suffixes (R4) 14
Enforced rule ENF-6