--- description: Hướng dẫn quản lý và sử dụng bộ Icon (Lucide Icons) trong Design System
Icon Component & Guidelines
Design System của chúng ta sử dụng bộ Lucide Icons (https://lucide.dev) làm quy chuẩn mặc định, đảm bảo tính thẩm mỹ, hiện đại và nhất quán trên toàn bộ các ứng dụng. Lucide là bộ icon open-source với 1,500+ icon, stroke-based, hỗ trợ currentColor hoàn hảo. Icon không được phép sử dụng kích thước hardcode (vd: 16px) mà phải được mapping từ hệ thống Icon Sizing Tokens.
⛔ CRITICAL RULES — ĐỌC TRƯỚC KHI SỬ DỤNG
Rule 1: CẤM DÙNG TEXT EMOJI THAY ICON KHÔNG BAO GIỜ sử dụng Unicode emoji (ℹ️ ✅ ⚠️ ❌ 🔍 🔔 📋 🗑 🖊 ⭐ ⬅️ ➡️...) để thay thế icon trong UI. Emoji hiển thị KHÔNG nhất quán giữa OS/browser, KHÔNG thể style bằng CSS, và phá vỡ design system. → PHẢI dùng SVG icon từ
design-system/assets/icons/.Rule 2: CẤM DÙNG ICON LIBRARY KHÁC CHỈ được phép sử dụng icon từ thư mục
design-system/assets/icons/. KHÔNG dùng: FontAwesome, Material Icons, Heroicons, Phosphor Icons, Tabler Icons, Ionicons, Feather Icons, hoặc bất kỳ bộ icon bên ngoài nào khác. Nếu cần icon chưa có → thêm từ Lucide vàoassets/icons/theo quy trình mục 8.Vi phạm 2 rule trên sẽ bị reject trong code review.
1. Tại sao chọn Lucide?
| Tiêu chí | Lucide Icons |
|---|---|
| Số lượng | 1,500+ icons, cập nhật hàng tuần |
| Phong cách | Stroke-based, clean, consistent |
| Màu sắc | Dùng currentColor → kế thừa từ parent |
| Kích thước mặc định | 24×24, viewBox 0 0 24 24 |
| Stroke width | Mặc định 2, có thể tuỳ chỉnh |
| License | ISC License (free for commercial use) |
| Framework support | React, Vue, Svelte, Angular, Web Components, SVG static |
| Package | lucide, lucide-react, lucide-vue-next, lucide-static |
2. Icon Variants
Lucide hỗ trợ tuỳ chỉnh thông qua stroke-width:
- Regular (stroke-width: 2): Sử dụng cho trạng thái mặc định. Phù hợp Sidebar, navigation-menu, Buttons.
- Light (stroke-width: 1.5): Sử dụng cho icon trang trí, minh họa, Empty State.
- Bold (stroke-width: 2.5): Sử dụng cho điểm nhấn mạnh, Active/Selected state.
Quy tắc sử dụng variant:
| Ngữ cảnh | Stroke-width | Ví dụ |
|---|---|---|
| Default / Inactive | 2 |
Sidebar, navigation-menu, Standard button |
| Active / Selected | 2.5 |
Active tab, Selected nav item |
| Trang trí / Minh họa | 1.5 |
Hero section, Empty state |
| Compact / Small | 2 |
Badge, Toast, Micro button |
3. Token Kích Thước (Icon Sizing)
Hệ thống token đã ánh xạ chuẩn (xem ATOMIC-MAPPING.md → mục icon). Bất kỳ icon nào cũng phải sử dụng một trong các biến kích thước này:
| Token Kích thước | Gốc (Spacing Token) | Kích thước | Ngữ cảnh sử dụng (Use case) |
|---|---|---|---|
var(--icon-sm) |
var(--spacing-4) |
16px | Badge, Hint text, Micro button, Input có kích thước hẹp. |
var(--icon-md) |
var(--spacing-5) |
20px | Nút bấm tiêu chuẩn (Standard Button), Input field, Dropdown. |
var(--icon-lg) |
var(--spacing-6) |
24px | Default Icon, navigation-menu, Sidebar tiêu chuẩn. |
var(--icon-xl) |
var(--spacing-8) |
32px | Icon đại diện trạng thái, Empty State, Layout lớn. |
var(--icon-2xl) |
var(--spacing-12) |
48px | Icon minh họa, Hero section, Empty State trọng tâm. |
4. Màu sắc (Icon Colors)
Tuyệt đối KHÔNG gán màu cứng (Hardcode) trực tiếp lên thẻ <svg> (Ví dụ: Không dùng <svg stroke="#FFFFFF">).
- Phải luôn sử dụng
stroke="currentColor"(cho outline icons) hoặcfill="currentColor"(cho filled icons). - Màu thực tế sẽ được Component bọc (wrapper) truyền xuống hoặc thông qua class tiện ích.
- CSS Example:css
/* Icon linh động tự kế thừa màu của cha */ .ds-icon { color: inherit; } /* Icon theo ngữ cảnh trạng thái */ .ds-icon-primary { color: var(--primary); } .ds-icon-muted { color: var(--muted-foreground); } .ds-icon-danger { color: var(--destructive); } .ds-icon-success { color: var(--success); } .ds-icon-warning { color: var(--warning); } .ds-icon-info { color: var(--info); }
5. Base CSS Classes bắt buộc
Khi triển khai trên UI, bạn BẮT BUỘC phải tạo ra base class quản lý Icon nhằm tránh bị vỡ layout trong Flexbox/Grid:
/* ds-icon: Base class bắt buộc cho mọi Lucide Icons */
.ds-icon {
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0; /* Rất quan trọng: Ngăn Flexbox bóp méo icon */
/* Kích thước mặc định */
width: var(--icon-lg);
height: var(--icon-lg);
color: inherit;
}
.ds-icon svg {
width: 100%;
height: 100%;
/* Lucide dùng stroke — KHÔNG fill */
fill: none;
stroke: currentColor;
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
}
/* Các biến thể kích thước */
.ds-icon-sm { width: var(--icon-sm); height: var(--icon-sm); }
.ds-icon-md { width: var(--icon-md); height: var(--icon-md); }
.ds-icon-lg { width: var(--icon-lg); height: var(--icon-lg); }
.ds-icon-xl { width: var(--icon-xl); height: var(--icon-xl); }
.ds-icon-2xl { width: var(--icon-2xl); height: var(--icon-2xl); }
6. Cấu trúc HTML áp dụng (Implementation)
Cách 1: Inline SVG (Khuyến nghị)
Copy SVG trực tiếp từ https://lucide.dev/icons:
<span class="ds-icon ds-icon-md ds-icon-primary">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="11" cy="11" r="8"/>
<path d="m21 21-4.3-4.3"/>
</svg>
</span>
Cách 2: Sử dụng tên icon từ assets
Reference SVG file trong design-system/assets/icons/:
<!-- Sử dụng img tag -->
<span class="ds-icon ds-icon-md">
<img src="assets/icons/search.svg" alt="Search" />
</span>
Cách 3: Framework (React/Vue/etc.)
// React
import { Search, Bell, User } from 'lucide-react';
<Search className="ds-icon ds-icon-md" />
<Bell size={20} />
<User size={24} strokeWidth={2} />
7. Bộ Icon mặc định (Default Set)
Design System bundle sẵn 42 icon phổ biến nhất, phân theo category:
Navigation (10 icons)
arrow-left arrow-right arrow-up arrow-down chevron-left chevron-right chevron-up chevron-down menu home
Action (14 icons)
plus minus x check search filter sliders-horizontal pencil trash copy upload download share link
Feedback (5 icons)
info triangle-alert circle-check circle-x bell
Content (8 icons)
file folder clipboard image calendar list grid layout-dashboard
User & Auth (5 icons)
user log-in log-out eye settings
Media & Social (5 icons)
star heart globe sun moon
Brand (1 icon)
github
8. Cách thêm Icon mới
- Vào https://lucide.dev/icons và tìm icon cần dùng
- Copy SVG code
- Đảm bảo SVG đã có:
fill="none"stroke="currentColor"stroke-width="2"stroke-linecap="round"stroke-linejoin="round" - Lưu file SVG vào
design-system/assets/icons/với tên kebab-case - Cập nhật
icon-catalog.tokens.json→ thêm tên icon vào category phù hợp - Chạy
node scripts/build-docs.jsđể cập nhật docs
9. Migration từ Heroicons
Nếu project cũ đang dùng Heroicons, lưu ý:
- Lucide icons dùng
strokethay vìfillcho variant outline - Thay đổi trong
.ds-icon svg:fill: currentColor→fill: none; stroke: currentColor - Hầu hết icon Lucide có tên tương đương với Heroicons (vd:
arrow-right,chevron-down,bell) - Xem bảng mapping đầy đủ tại: https://lucide.dev/guide/comparison
10. ⛔ Governance — Quy tắc bắt buộc
10.1. CẤM tuyệt đối dùng Text Emoji thay Icon
| ❌ SAI (Emoji) | ✅ ĐÚNG (Lucide SVG) | Tên icon file |
|---|---|---|
| ℹ️ | <span class="ds-icon"><svg>...</svg></span> |
info.svg |
| ✅ | <span class="ds-icon"><svg>...</svg></span> |
circle-check.svg |
| ⚠️ | <span class="ds-icon"><svg>...</svg></span> |
triangle-alert.svg |
| ❌ | <span class="ds-icon"><svg>...</svg></span> |
circle-x.svg |
| 🔍 | <span class="ds-icon"><svg>...</svg></span> |
search.svg |
| 🔔 | <span class="ds-icon"><svg>...</svg></span> |
bell.svg |
| 📋 | <span class="ds-icon"><svg>...</svg></span> |
clipboard.svg |
| 🗑 | <span class="ds-icon"><svg>...</svg></span> |
trash.svg |
| ✏️ | <span class="ds-icon"><svg>...</svg></span> |
pencil.svg |
| ⭐ | <span class="ds-icon"><svg>...</svg></span> |
star.svg |
| ❤️ | <span class="ds-icon"><svg>...</svg></span> |
heart.svg |
Lý do:
- Emoji hiển thị khác nhau giữa Windows, macOS, iOS, Android
- Emoji KHÔNG thể điều chỉnh
color,size,stroke-widthqua CSS - Emoji phá vỡ visual consistency của design system
- Emoji có kích thước không đồng nhất giữa các font
10.2. CẤM dùng Icon Library ngoài danh sách cho phép
Chỉ được phép dùng icon từ:
design-system/assets/icons/ ← 53 icons hiện tại
KHÔNG được phép import/reference:
- ❌ FontAwesome (
fa-*) - ❌ Material Icons (
material-icons) - ❌ Heroicons (
@heroicons/*) - ❌ Phosphor Icons (
phosphor-icons) - ❌ Tabler Icons (
@tabler/icons) - ❌ Ionicons (
ionicons) - ❌ Feather Icons (
feather-icons) - ❌ Bootstrap Icons (
bi-*) - ❌ Bất kỳ CDN icon nào
Nếu cần icon chưa có: Theo quy trình mục 8 để thêm icon mới từ Lucide.
10.3. Mapping Icon theo Component
Các component PHẢI sử dụng đúng icon được chỉ định:
| Component | Ngữ cảnh | Icon bắt buộc (Lucide name) |
|---|---|---|
| Alert (info) | Icon trạng thái | info |
| Alert (success) | Icon trạng thái | circle-check |
| Alert (warning) | Icon trạng thái | triangle-alert |
| Alert (destructive) | Icon trạng thái | circle-x |
| Toast (info/default) | Icon trạng thái | info |
| Toast (success) | Icon trạng thái | circle-check |
| Toast (warning) | Icon trạng thái | triangle-alert |
| Toast (destructive) | Icon trạng thái | circle-x |
| Modal / Drawer | Close button | x |
| Accordion | Expand indicator | chevron-down |
| Breadcrumb | Separator | chevron-right |
| Breadcrumb | Home icon | home |
| Input (search) | Leading icon | search |
| Input (password) | Toggle visibility | eye |
| Select | Dropdown arrow | chevron-down |
| Checkbox | Checked state | check |
| navigation-menu | Search action | search |
| navigation-menu | Notifications | bell |
| navigation-menu | Mobile menu | menu |
| Sidebar | Collapse toggle | chevron-left / chevron-right |
| Dropdown | Delete action | trash |
| Dropdown | Copy action | copy |
| Dropdown | Edit action | pencil |
| Dropdown | Share action | share |
| Badge | Close/remove | x |
| Empty State | Illustration | Theo ngữ cảnh (file, search, inbox...) |