Documentation
Init UI là một CSS framework nhỏ gọn, có ý kiến riêng (opinionated) — tập trung vào tốc độ phát triển
và khả năng tuỳ biến. Toàn bộ bảng màu được sinh từ một biến gốc duy nhất bằng
oklch(). Dark mode, Toast, Modal, Command Palette và hàng chục component khác
sẵn sàng hoạt động mà không cần dependency nào.
Cài đặt
Init UI không có dependency. Bạn có thể sử dụng qua CDN, hoặc tải trực tiếp.
CDN
<link rel="stylesheet" href="https://r2.inithtml.com/init-ui/css/init-ui.min.css" /> <script src="https://r2.inithtml.com/init-ui/js/init-ui.min.js"></script>
Tải trực tiếp
Tải init-ui.min.css và init-ui.min.js từ repository, đặt vào dự án và link đến chúng.
Browser Support
Init UI dùng một số tính năng CSS hiện đại — oklch(), color-mix(), @layer, và prefers-reduced-motion — để sinh palette và animation. Các trình duyệt dưới đây được hỗ trợ đầy đủ:
Trên trình duyệt cũ hơn, các thang màu sinh từ oklch() sẽ không lên đúng — nên kiểm tra caniuse.com nếu dự án của bạn cần hỗ trợ trình duyệt cũ hơn mốc trên.
Quick Start
Dưới đây là template HTML tối thiểu để bắt đầu. Nó đã bao gồm dark mode, theme toggle, và font Inter.
<!doctype html> <html lang="vi" data-theme="auto"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>My App</title> <link rel="stylesheet" href="css/init-ui.css" /> </head> <body> <button class="iu-btn iu-btn--primary">Hello World!</button> <script src="js/init-ui.js"></script> </body> </html>
Sau khi include init-ui.js, toàn bộ Data API sẽ tự động hoạt động: theme toggle, modal, offcanvas, dropdown, tooltip, tabs, v.v. Bạn không cần viết thêm JavaScript.
Dọn dẹp trong SPA
Nếu dùng Init UI trong React/Vue/Svelte, gọi InitUI.destroy() trước khi component/route bị unmount để đóng toast, modal, dropdown đang mở và ngắt MutationObserver của icon — tránh giữ tham chiếu đến node DOM đã bị xoá. Không cần gọi lại hàm khởi tạo nào sau đó; các listener ở cấp document vẫn hoạt động bình thường và an toàn khi gọi lại nhiều lần.
// Trước khi component/route bị unmount InitUI.destroy();
Theming
Init UI sử dụng oklch(from ...) để sinh toàn bộ thang màu từ một biến gốc. Đổi màu chủ đạo chỉ cần ghi đè một dòng CSS:
:root {
--iu-primary-base: oklch(58% 0.19 300); /* Violet */
}
Toàn bộ palette 11 sắc độ (50→950), gradient, focus ring, và contrast pairs sẽ tự động cập nhật. Không cần khai báo lại từng shade.
Biến gốc
Có 6 biến gốc, mỗi biến sinh ra một thang màu ngữ nghĩa riêng. Ghi đè bất kỳ biến nào trong số này để đổi toàn bộ thang màu tương ứng:
| Biến | Ý nghĩa | Mặc định |
|---|---|---|
--iu-primary-base | Màu chủ đạo — CTA, link, focus | oklch(58% 0.135 165) |
--iu-neutral-base | Xám nền, text, border | oklch(50% 0.006 165) |
--iu-success-base | Trạng thái thành công | oklch(55% 0.14 150) |
--iu-danger-base | Trạng thái lỗi, nguy hiểm | oklch(55% 0.19 25) |
--iu-warning-base | Trạng thái cảnh báo | oklch(70% 0.15 80) |
--iu-info-base | Thông tin, trung tính-xanh | oklch(55% 0.14 235) |
Live Theme Playground
Kéo màu bên dưới để xem --iu-primary-base đổi ngay trên các component thật. Thay đổi chỉ áp dụng cho phiên xem hiện tại, không lưu lại.
Semantic Aliases
Nếu bạn cần điều chỉnh sâu hơn, ghi đè các alias ngữ nghĩa:
:root {
--iu-color-bg: #fafafa;
--iu-color-text: #111;
--iu-color-border: #e5e5e5;
--iu-color-link: var(--iu-primary-700);
}
Dark Mode
Dark mode được xây dựng sẵn và tự động. Có 3 chế độ:
data-theme="auto"— tự động theoprefers-color-scheme(mặc định)data-theme="light"— ép sángdata-theme="dark"— ép tối
<button class="iu-btn iu-btn--secondary" data-iu-theme-toggle>Toggle Theme</button>
JavaScript API
InitUI.theme.toggle(); // Toggle light/dark
InitUI.theme.apply("dark"); // Set explicitly
InitUI.theme.get(); // "auto" | "light" | "dark"
InitUI.theme.resolvedTheme(); // "light" | "dark" (resolved)
Chống FOUC
Để tránh flash trắng khi tải trang ở dark mode, chèn đoạn script sau vào <head>, trước cả khi link CSS:
<script>
(function () {
try {
var theme = localStorage.getItem("iu-theme") || "auto";
document.documentElement.setAttribute("data-theme", theme);
} catch (e) {
document.documentElement.setAttribute("data-theme", "auto");
}
})();
</script>
Cách này đặt theme trước khi browser render bất kỳ CSS nào, loại bỏ hoàn toàn flash sáng khi người dùng đã chọn dark mode từ lần trước.
Icons
Init UI đi kèm bộ icon SVG dựng sẵn — không icon font, không request ra ngoài. Icon được đăng ký ngay trong init-ui.js và tự "hydrate" qua MutationObserver, nên bạn có thể chèn data-icon vào DOM bất cứ lúc nào (kể cả từ React/Vue) mà không cần gọi lại hàm khởi tạo nào.
Cách dùng
Thêm <span class="iu-icon" data-icon="tên-icon"></span> vào bất kỳ đâu trong HTML. Kích thước mặc định 1.25rem (20px), màu kế thừa currentColor — chỉnh cỡ qua style/CSS, chỉnh màu qua class iu-text-* hoặc color.
<span class="iu-icon" data-icon="heart"></span>
<span class="iu-icon iu-text-danger" data-icon="heart" style="width:1.75rem;height:1.75rem;"></span>
<span class="iu-icon iu-text-primary" data-icon="star" style="width:2.5rem;height:2.5rem;"></span>
<button class="iu-btn iu-btn--primary">
<span class="iu-icon" data-icon="download"></span> Tải xuống
</button>
Danh sách Icon
48 icon có sẵn, chia thành hai nhóm bên dưới. Dùng đúng tên trong khung — ví dụ tên check ứng với data-icon="check".
Thêm Icon Tuỳ Chỉnh
Không giới hạn ở 48 icon có sẵn — đăng ký icon SVG riêng bằng InitUI.icon.add(name, svgString), sau đó dùng data-icon="name" y hệt icon dựng sẵn:
InitUI.icon.add("rocket", '<svg viewBox="0 0 24 24" fill="currentColor" width="100%" height="100%"><path d="..."/></svg>');
<span class="iu-icon" data-icon="rocket"></span>
SVG xuất từ Figma/Illustrator thường kèm theo metadata, id, comment thừa — làm phình
init-ui.js một cách không cần thiết. Hãy tối ưu SVG (bỏ thuộc tính thừa, làm tròn số thập phân, gộp path) trước khi dán vào InitUI.icon.add() hoặc dùng trực tiếp trong HTML. Dùng công cụ miễn phí Init SVG Optimizer để nén icon chỉ trong một bước.JavaScript API
| Method | Mô tả |
|---|---|
InitUI.icon.add(name, svgString) | Đăng ký (hoặc ghi đè) một icon mới. |
InitUI.icon.render(name, attrs) | Trả về chuỗi HTML <span class="iu-icon">...</span> — dùng khi build HTML bằng JS. |
InitUI.icon.inject(name, target, attrs) | Chèn icon vào cuối một element (theo selector hoặc tham chiếu DOM). |
InitUI.icon.hydrateAll(root) | Quét lại toàn bộ trang (hoặc trong root) và hydrate mọi [data-icon] chưa render. |
InitUI.icon.destroy() | Ngắt MutationObserver — gọi trước khi unmount trong SPA. |
Container
Container căn giữa nội dung và giới hạn max-width. Có 4 biến thể:
.iu-container— max-width: 1200px (mặc định).iu-container--sm— max-width: 720px.iu-container--lg— max-width: 1440px.iu-container--fluid— full width
<div class="iu-container" style="background:var(--iu-primary-100);padding:1rem;border-radius:var(--iu-radius-md);text-align:center;">Default container</div>
<div class="iu-container--sm iu-mt-3" style="background:var(--iu-primary-100);padding:1rem;border-radius:var(--iu-radius-md);text-align:center;">Small container</div>
Grid
Grid system dựa trên CSS Grid với custom properties. Điều chỉnh số cột qua --iu-cols và khoảng cách qua --iu-gap.
<div class="iu-grid" style="--iu-cols: 3; --iu-gap: 1rem;">
<div>Column 1</div>
<div>Column 2</div>
<div>Column 3</div>
</div>
Auto-fit Grid
Dùng .iu-grid--auto để tự động fit các cột theo min-width:
<div class="iu-grid iu-grid--auto" style="--iu-min-col:140px;--iu-gap:1rem;">
<div style="background:var(--iu-primary-100);padding:1rem;border-radius:var(--iu-radius-md);">Auto</div>
<div style="background:var(--iu-primary-100);padding:1rem;border-radius:var(--iu-radius-md);">Fit</div>
<div style="background:var(--iu-primary-100);padding:1rem;border-radius:var(--iu-radius-md);">Grid</div>
<div style="background:var(--iu-primary-100);padding:1rem;border-radius:var(--iu-radius-md);">Columns</div>
</div>
Column Span
Sử dụng .iu-col-{1,2,3,4,6,12} để điều khiển độ rộng cột:
<div class="iu-grid" style="--iu-cols:4;--iu-gap:1rem;">
<div class="iu-col-2" style="background:var(--iu-primary-200);padding:1rem;border-radius:var(--iu-radius-md);">.iu-col-2</div>
<div style="background:var(--iu-primary-100);padding:1rem;border-radius:var(--iu-radius-md);">auto</div>
<div style="background:var(--iu-primary-100);padding:1rem;border-radius:var(--iu-radius-md);">auto</div>
</div>
Stack
Stack tạo khoảng cách dọc đều đặn giữa các phần tử con, tránh vấn đề margin collapsing. Điều chỉnh gap qua --iu-gap.
<div class="iu-stack" style="--iu-gap:1rem;">
<div style="background:var(--iu-primary-100);padding:1rem;border-radius:var(--iu-radius-md);">Item 1</div>
<div style="background:var(--iu-primary-100);padding:1rem;border-radius:var(--iu-radius-md);">Item 2</div>
<div style="background:var(--iu-primary-100);padding:1rem;border-radius:var(--iu-radius-md);">Item 3</div>
</div>
Cluster
Cluster là một flex container inline với flex-wrap, lý tưởng cho các nhóm button, tag, hoặc metadata. Điều chỉnh gap qua --iu-gap.
<div class="iu-cluster" style="--iu-gap:0.75rem;">
<span class="iu-badge iu-badge--primary">Design</span>
<span class="iu-badge iu-badge--success">Dev</span>
<span class="iu-badge iu-badge--info">Docs</span>
<span class="iu-badge iu-badge--warning">Beta</span>
</div>
Flex Utilities
Tập hợp các utility class cho flexbox:
| Class | CSS |
|---|---|
.iu-flex | display: flex |
.iu-flex-col | flex-direction: column |
.iu-flex-wrap | flex-wrap: wrap |
.iu-items-center | align-items: center |
.iu-justify-between | justify-content: space-between |
.iu-grow | flex-grow: 1 |
.iu-shrink-0 | flex-shrink: 0 |
Card
Card là container có nền surface, viền, và bo góc. Có hiệu ứng hover nâng cao với .iu-card--hover.
Card tiêu chuẩn
Viền mảnh, bo góc lg, đổ bóng nhẹ — nâng lên khi hover.
Card Gradient
Sử dụng gradient token làm nền.
Card đơn giản
Không hover effect, chỉ nền và viền cơ bản.
<div class="iu-grid" style="--iu-cols:3;--iu-gap:1rem;">
<div class="iu-card iu-card--hover">
<div class="iu-card__body">
<p class="iu-card__title">Card tiêu chuẩn</p>
<p class="iu-card__text">Viền mảnh, bo góc lg, đổ bóng nhẹ — nâng lên khi hover.</p>
</div>
<div class="iu-card__footer">
<button class="iu-btn iu-btn--sm iu-btn--secondary">Chi tiết</button>
</div>
</div>
<div class="iu-card iu-card--gradient">
<div class="iu-card__body">
<p class="iu-card__title">Card Gradient</p>
<p class="iu-card__text">Sử dụng gradient token làm nền.</p>
</div>
</div>
<div class="iu-card">
<div class="iu-card__body">
<p class="iu-card__title">Card đơn giản</p>
<p class="iu-card__text">Không hover effect, chỉ nền và viền cơ bản.</p>
</div>
</div>
</div>
Class Reference
| Class | Mô tả |
|---|---|
.iu-card | Base card |
.iu-card--hover | Hiệu ứng nâng khi hover |
.iu-card--gradient | Nền gradient soft |
.iu-card__body | Padding nội dung |
.iu-card__title | Tiêu đề card |
.iu-card__text | Mô tả card (muted) |
.iu-card__footer | Vùng footer có border-top |
.iu-card__media | Chứa ảnh/video (16:9) |
Badge
Badge dùng để hiển thị trạng thái, tag, hoặc label nhỏ. Hỗ trợ dot indicator và solid variant.
<div class="iu-cluster" style="--iu-gap:0.75rem;">
<span class="iu-badge iu-badge--primary">Primary</span>
<span class="iu-badge iu-badge--success">Success</span>
<span class="iu-badge iu-badge--danger">Danger</span>
<span class="iu-badge iu-badge--warning">Warning</span>
<span class="iu-badge iu-badge--info">Info</span>
<span class="iu-badge iu-badge--dot iu-badge--primary">Online</span>
</div>
Solid Badges
<div class="iu-cluster" style="--iu-gap:0.75rem;">
<span class="iu-badge iu-badge--solid iu-badge--primary">Solid</span>
</div>
Alert
Alert hiển thị thông báo quan trọng với màu sắc ngữ cảnh. Có thể đóng bằng nút close.
Đã lưu thay đổi.
Phiên bản đang thử nghiệm.
Không thể kết nối.
<div class="iu-stack" style="--iu-gap:0.75rem;">
<div class="iu-alert iu-alert--success">
<div class="iu-alert__body"><span class="iu-alert__title">Thành công!</span><br>Đã lưu thay đổi.</div>
<button type="button" class="iu-alert__close" aria-label="Đóng"><span class="iu-icon" data-icon="close"></span></button>
</div>
<div class="iu-alert iu-alert--warning">
<div class="iu-alert__body"><span class="iu-alert__title">Chú ý</span><br>Phiên bản đang thử nghiệm.</div>
<button type="button" class="iu-alert__close" aria-label="Đóng"><span class="iu-icon" data-icon="close"></span></button>
</div>
<div class="iu-alert iu-alert--danger">
<div class="iu-alert__body"><span class="iu-alert__title">Lỗi</span><br>Không thể kết nối.</div>
<button type="button" class="iu-alert__close" aria-label="Đóng"><span class="iu-icon" data-icon="close"></span></button>
</div>
</div>
Nút close tự động được xử lý bởi init-ui.js. Click vào .iu-alert__close sẽ trigger animation rồi remove element.
Form Input
Các control form được style đồng bộ với border, focus ring, và trạng thái invalid.
Input cơ bản
<div class="iu-field">
<label class="iu-label" for="demoName">Họ và tên</label>
<input class="iu-input" type="text" id="demoName" placeholder="Nguyễn Văn A" />
</div>
<div class="iu-field iu-mt-4">
<label class="iu-label" for="demoEmail">Email</label>
<input class="iu-input" type="email" id="demoEmail" placeholder="[email protected]" aria-invalid="true" />
<span class="iu-hint iu-text-danger">Email không hợp lệ.</span>
</div>
Input với Icon
<div class="iu-field">
<label class="iu-label" for="demoSearch">Tìm kiếm</label>
<div class="iu-input--icon">
<span class="iu-icon" data-icon="search"></span>
<input class="iu-input" type="search" id="demoSearch" placeholder="Nhập từ khóa..." />
</div>
</div>
Select
<div class="iu-field">
<label class="iu-label" for="demoRole">Vai trò</label>
<select class="iu-select" id="demoRole">
<option>Developer</option>
<option>Designer</option>
<option>Product Manager</option>
</select>
</div>
Textarea
<div class="iu-field">
<label class="iu-label" for="demoMsg">Lời nhắn</label>
<textarea class="iu-textarea" id="demoMsg" placeholder="Nhập nội dung..."></textarea>
</div>
Class Reference
| Class | Mô tả |
|---|---|
.iu-field | Wrapper label + input + hint |
.iu-label | Label form |
.iu-input | Text input |
.iu-select | Select dropdown (custom arrow) |
.iu-textarea | Textarea (resize: vertical) |
.iu-hint | Helper text dưới input |
.iu-input--icon | Input có icon bên trái |
[aria-invalid="true"] | Viền đỏ (danger) |
Checkbox & Radio
Checkbox và Radio được custom hoàn toàn bằng CSS, không cần JS. Hỗ trợ focus-visible và checked states.
<div class="iu-stack" style="--iu-gap:0.75rem;">
<label class="iu-cluster" style="--iu-gap:0.6rem;">
<input type="checkbox" class="iu-check" checked />
<span class="iu-text-sm">Tôi đồng ý với điều khoản</span>
</label>
<label class="iu-cluster" style="--iu-gap:0.6rem;">
<input type="checkbox" class="iu-check" />
<span class="iu-text-sm">Nhận email cập nhật</span>
</label>
<div class="iu-divider--label" role="separator">Chọn gói</div>
<label class="iu-cluster" style="--iu-gap:0.6rem;">
<input type="radio" name="plan" class="iu-radio" checked />
<span class="iu-text-sm">Miễn phí</span>
</label>
<label class="iu-cluster" style="--iu-gap:0.6rem;">
<input type="radio" name="plan" class="iu-radio" />
<span class="iu-text-sm">Pro</span>
</label>
</div>
Switch
Switch toggle với animation mượt mà. Sử dụng native checkbox nên hoạt động hoàn hảo với form.
<label class="iu-cluster" style="--iu-gap:0.5rem;">
<input type="checkbox" class="iu-switch" checked />
<span class="iu-text-sm">Bật thông báo</span>
</label>
Password Input
Input mật khẩu có nút toggle hiển thị/ẩn. Tự động inject icon eye/eye-off từ Icon module.
<div class="iu-field">
<label class="iu-label" for="demoPass">Mật khẩu</label>
<div class="iu-input--password-wrap">
<input class="iu-input" type="password" id="demoPass" placeholder="••••••••" />
<button type="button" class="iu-input__eye" aria-label="Hiện mật khẩu" tabindex="-1"></button>
</div>
</div>
Yêu cầu cấu trúc: .iu-input--password-wrap chứa input và button.iu-input__eye. JS sẽ tự động xử lý toggle và icon.
Tabs
Tabs với keyboard navigation (Arrow, Home, End) và fade animation khi chuyển panel. Tự động init qua init-ui.js.
Nội dung tổng quan.
Nội dung cài đặt.
Nội dung bảo mật.
<div class="iu-tabs">
<div class="iu-tab-list">
<button class="iu-tab">Tổng quan</button>
<button class="iu-tab">Cài đặt</button>
<button class="iu-tab">Bảo mật</button>
</div>
<div class="iu-tab-panel">
<p class="iu-text-sm iu-text-muted">Nội dung tổng quan.</p>
</div>
<div class="iu-tab-panel">
<p class="iu-text-sm iu-text-muted">Nội dung cài đặt.</p>
</div>
<div class="iu-tab-panel">
<p class="iu-text-sm iu-text-muted">Nội dung bảo mật.</p>
</div>
</div>
Cấu trúc yêu cầu: .iu-tabs > .iu-tab-list chứa các .iu-tab, và các .iu-tab-panel ngang hàng. Không cần thêm attribute nào — JS tự gán role, aria-selected, và tabindex.
Modal
Modal với overlay backdrop blur, focus trap, đóng bằng Esc hoặc click ngoài. Scroll lock tự động.
<button class="iu-btn iu-btn--primary" data-iu-modal-open="docsModal">Mở Modal</button>
<div class="iu-modal-overlay" id="docsModal" data-open="false">
<div class="iu-modal" role="dialog" aria-modal="true" aria-labelledby="docsModalTitle">
<div class="iu-modal__header">
<div>
<p class="iu-modal__title" id="docsModalTitle">Xác nhận</p>
<p class="iu-modal__description">Mô tả hành động cần xác nhận.</p>
</div>
<button class="iu-modal__close" data-iu-modal-close aria-label="Đóng">
<span class="iu-icon" data-icon="close" aria-hidden="true"></span>
</button>
</div>
<div class="iu-modal__body">
<p>Nội dung modal ở đây.</p>
</div>
<div class="iu-modal__footer">
<button class="iu-btn iu-btn--secondary" data-iu-modal-close>Huỷ</button>
<button class="iu-btn iu-btn--primary" data-iu-modal-close>Xác nhận</button>
</div>
</div>
</div>
JavaScript API
InitUI.modal.open("docsModal"); // Mở modal theo ID
InitUI.modal.close("docsModal"); // Đóng modal
InitUI.modal.open(element); // Hoặc truyền element trực tiếp
Class Reference
| Class | Mô tả |
|---|---|
.iu-modal-overlay | Backdrop + wrapper |
.iu-modal | Dialog box |
.iu-modal--sm / --lg | Kích thước |
.iu-modal__header | Tiêu đề + close |
.iu-modal__title | Tiêu đề |
.iu-modal__description | Mô tả phụ |
.iu-modal__body | Nội dung chính |
.iu-modal__footer | Nút hành động |
[data-iu-modal-open] | Trigger mở (value = id) |
[data-iu-modal-close] | Trigger đóng |
Offcanvas
Panel trượt vào từ trái hoặc phải. Cùng cơ chế mở/đóng với Modal nhưng hiệu ứng trượt khác biệt.
<button class="iu-btn iu-btn--outline" data-iu-offcanvas-open="docsOffcanvas">Mở Offcanvas</button>
<div class="iu-offcanvas-overlay" id="docsOffcanvas" data-open="false">
<div class="iu-offcanvas iu-offcanvas--right" role="dialog" aria-label="Panel phụ">
<div class="iu-offcanvas__header">
<strong>Chi tiết</strong>
<button class="iu-btn iu-btn--icon iu-btn--ghost" data-iu-offcanvas-close aria-label="Đóng">
<span class="iu-icon" data-icon="close" aria-hidden="true"></span>
</button>
</div>
<div class="iu-offcanvas__body">
<p class="iu-text-sm iu-text-muted">Nội dung panel ở đây.</p>
</div>
</div>
</div>
JavaScript API
InitUI.offcanvas.open("docsOffcanvas");
InitUI.offcanvas.close("docsOffcanvas");
Dropdown
Dropdown menu với click trigger, hover support cho navbar, và keyboard navigation (Arrow, Escape).
<div class="iu-dropdown">
<button class="iu-btn iu-btn--secondary" data-iu-dropdown-trigger>Mở menu</button>
<div class="iu-dropdown__menu">
<a href="#" class="iu-dropdown__item">Xem chi tiết</a>
<a href="#" class="iu-dropdown__item">Chỉnh sửa</a>
<div class="iu-dropdown__divider"></div>
<a href="#" class="iu-dropdown__item iu-dropdown__item--danger">Xóa</a>
</div>
</div>
Dropdown trong navbar sử dụng chung engine nhưng với class .iu-navbar__dropdown và .iu-navbar__dropdown-item.
Toast
Thông báo nổi linh hoạt với 6 vị trí, progress bar, pause on hover, và sticky mode. Gọi qua InitUI.toast API.
Demo
<div class="iu-cluster" style="--iu-gap:0.75rem;">
<button class="iu-btn iu-btn--secondary" onclick="InitUI.toast.show({title:'Thông báo',message:'Toast mặc định.'})">Default</button>
<button class="iu-btn iu-btn--secondary" onclick="InitUI.toast.success('Lưu thành công!',{title:'Hoàn tất'})">Success</button>
<button class="iu-btn iu-btn--secondary" onclick="InitUI.toast.danger('Không thể kết nối.',{title:'Lỗi'})">Danger</button>
<button class="iu-btn iu-btn--secondary" onclick="InitUI.toast.warning('Phiên sắp hết hạn.',{title:'Cảnh báo'})">Warning</button>
<button class="iu-btn iu-btn--secondary" onclick="InitUI.toast.info('Có bản cập nhật mới.',{title:'Thông tin'})">Info</button>
<button class="iu-btn iu-btn--secondary" onclick="InitUI.toast.show({title:'Toast dính',message:'Không tự tắt — bấm X để đóng.',duration:0,type:'info'})">Sticky</button>
</div>
JavaScript API
InitUI.toast.show({
title: "Tiêu đề",
message: "Nội dung chi tiết...",
type: "success", // default | success | danger | warning | info
duration: 4000, // ms; 0 = sticky
position: "top-right", // top-right | top-left | bottom-right | bottom-left | top-center | bottom-center
closable: true
});
// Shorthand
InitUI.toast.success("Message", { title: "Done" });
InitUI.toast.danger("Message", { title: "Error" });
InitUI.toast.warning("Message", { title: "Warn" });
InitUI.toast.info("Message", { title: "Info" });
Tooltip
Tooltip JS-driven với smart placement (tự động flip nếu không đủ chỗ), arrow luôn chỉ đúng trigger. Không cần thêm CSS positioning.
<div class="iu-cluster" style="--iu-gap:1rem;">
<button class="iu-btn iu-btn--secondary" data-tooltip="Tooltip mặc định ở trên">Hover me</button>
<button class="iu-btn iu-btn--secondary" data-tooltip="Hiện phía dưới" data-tooltip-position="bottom">Bottom</button>
<button class="iu-btn iu-btn--secondary" data-tooltip="Hiện bên trái" data-tooltip-position="left">Left</button>
<button class="iu-btn iu-btn--secondary" data-tooltip="Hiện bên phải" data-tooltip-position="right">Right</button>
</div>
Chỉ cần thêm data-tooltip="text" lên bất kỳ element nào. Tùy chọn data-tooltip-position="top|bottom|left|right" để chỉ định vị trí ưu tiên.
Progress
Progress bar và progress ring với gradient support và indeterminate mode.
Progress Bar
<div class="iu-stack" style="--iu-gap:1rem;">
<div class="iu-progress"><div class="iu-progress__bar" style="--iu-progress-value:72%;"></div></div>
<div class="iu-progress"><div class="iu-progress__bar iu-progress__bar--gradient" style="--iu-progress-value:45%;"></div></div>
<div class="iu-progress iu-progress--indeterminate"><div class="iu-progress__bar"></div></div>
</div>
Progress Ring
<div class="iu-cluster" style="--iu-gap:1.5rem;align-items:center;">
<div class="iu-progress-ring" style="--iu-progress-value:68;"></div>
<span class="iu-text-sm iu-text-muted">68% hoàn thành</span>
</div>
Class Reference
| Class | Mô tả |
|---|---|
.iu-progress | Bar container |
.iu-progress__bar | Thanh tiến độ (set --iu-progress-value) |
.iu-progress__bar--gradient | Gradient fill |
.iu-progress--indeterminate | Animation vô hạn |
.iu-progress--sm / --lg | Kích thước |
.iu-progress-ring | Vòng tròn (set --iu-progress-value 0-100) |
Avatar
Avatar hình tròn với gradient nền. Hỗ trợ text fallback hoặc emoji.
<div class="iu-cluster" style="--iu-gap:1rem;">
<span class="iu-avatar iu-avatar--sm">H</span>
<span class="iu-avatar">HN</span>
<span class="iu-avatar iu-avatar--lg">🌱</span>
</div>
Skeleton
Loading placeholder với wave animation. Sử dụng background gradient và background-size: 200%.
<div class="iu-cluster" style="--iu-gap:0.5rem;">
<span class="iu-skeleton" style="width:2.5rem;height:2.5rem;border-radius:999px;"></span>
<div class="iu-stack" style="--iu-gap:0.4rem;">
<span class="iu-skeleton" style="width:8rem;height:0.75rem;"></span>
<span class="iu-skeleton" style="width:5rem;height:0.75rem;"></span>
</div>
</div>
Divider
Divider cơ bản và divider có label ở giữa.
Nội dung phía trên
Nội dung phía dưới
<div class="iu-stack" style="--iu-gap:1rem;">
<p>Nội dung phía trên</p>
<hr class="iu-divider" />
<p>Nội dung phía dưới</p>
<div class="iu-divider--label" role="separator">Hoặc tiếp tục với</div>
</div>
List
List với icon leading, divider giữa các item, và marker dash.
- Zero dependency Vanilla JS, không cần build step
- Theme tự sinh Đổi 1 biến là đổi cả bảng màu
<ul class="iu-list iu-list--divided">
<li class="iu-list__item">
<span class="iu-list__icon" aria-hidden="true">✓</span>
<span>
<span class="iu-list__title">Zero dependency</span>
<span class="iu-list__desc" style="display:block;">Vanilla JS, không cần build step</span>
</span>
</li>
<li class="iu-list__item">
<span class="iu-list__icon" aria-hidden="true">✓</span>
<span>
<span class="iu-list__title">Theme tự sinh</span>
<span class="iu-list__desc" style="display:block;">Đổi 1 biến là đổi cả bảng màu</span>
</span>
</li>
</ul>
Table
Table với striped, hover, compact variants. Wrap trong .iu-table-wrap để scroll ngang trên mobile.
| Component | Trạng thái | Từ bản |
|---|---|---|
| Button | Ổn định | v0.1.0 |
| Card | Ổn định | v0.1.0 |
| Toast | Ổn định | v0.1.0 |
<div class="iu-table-wrap">
<table class="iu-table iu-table--striped iu-table--hover">
<thead>
<tr><th>Component</th><th>Trạng thái</th><th>Từ bản</th></tr>
</thead>
<tbody>
<tr><td>Button</td><td><span class="iu-badge iu-badge--success iu-badge--dot">Ổn định</span></td><td><code>v0.1.0</code></td></tr>
<tr><td>Card</td><td><span class="iu-badge iu-badge--success iu-badge--dot">Ổn định</span></td><td><code>v0.1.0</code></td></tr>
<tr><td>Toast</td><td><span class="iu-badge iu-badge--success iu-badge--dot">Ổn định</span></td><td><code>v0.1.0</code></td></tr>
</tbody>
</table>
</div>
Back To Top
Nút quay về đầu trang, hiện khi scroll quá ngưỡng (mặc định 400px). Tự động smooth scroll.
Thêm vào HTML:
<button class="iu-back-to-top" data-iu-back-to-top data-iu-threshold="300" aria-label="Về đầu trang"> <span class="iu-icon" data-icon="arrow-top"></span> </button>
Nút này đã được thêm ở cuối trang documentation này. Thử scroll xuống để xem nó xuất hiện.
Command Palette
Overlay tìm kiếm toàn trang với filter real-time, keyboard navigation (Arrow, Enter, Escape), và grouping. Mở bằng CtrlK hoặc click Search Trigger trên navbar.
Command Palette trên trang này đã được tích hợp sẵn — nhấn CtrlK để thử tìm kiếm tài liệu.
Cấu trúc HTML
<div class="iu-command-overlay" id="cmd" data-open="false">
<div class="iu-command" role="dialog">
<div class="iu-command__input-wrap">...</div>
<div class="iu-command__list">
<div class="iu-command__group">...</div>
</div>
</div>
</div>
JavaScript API
InitUI.command.open("cmd"); // Mở palette theo ID
InitUI.command.close("cmd"); // Đóng palette
Kbd
Hiển thị phím tắt với phong cách bàn phím vật lý — nền surface, viền đậm dưới, font monospace.
Nhấn CtrlK để mở Command Palette. Nhấn Esc để đóng.
<p>Nhấn <kbd class="iu-kbd">Ctrl</kbd><kbd class="iu-kbd">K</kbd> để mở Command Palette.
Nhấn <kbd class="iu-kbd">Esc</kbd> để đóng.</p>
Search Trigger
Pill button mở Command Palette. Tích hợp sẵn icon search, placeholder text, và Kbd hint. Trên mobile tự động thu gọn thành icon.
<button class="iu-search-trigger" data-iu-command-open>
<span class="iu-icon" data-icon="search" aria-hidden="true"></span>
<span class="iu-search-trigger__label">Tìm kiếm...</span>
<span class="iu-kbd">Ctrl</span><span class="iu-kbd">K</span>
</button>
Accordion
Accordion với chế độ single/multiple, animation mượt mà bằng CSS grid. Tự động init qua init-ui.js.
Nội dung accordion 1.
Nội dung accordion 2.
<div class="iu-accordion" data-iu-accordion data-iu-accordion-mode="single">
<div class="iu-accordion__item" data-open="true">
<h3 class="iu-accordion__header">
<button type="button" class="iu-accordion__trigger">
Mục 1
<svg class="iu-accordion__icon" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">...</svg>
</button>
</h3>
<div class="iu-accordion__panel">
<div class="iu-accordion__body-inner">Nội dung accordion 1.</div>
</div>
</div>
</div>
JavaScript API
InitUI.accordion.toggle(item); // Toggle one item InitUI.accordion.collapseAll(); // Close all items
Class Reference
| Class | Mô tả |
|---|---|
.iu-accordion | Wrapper |
.iu-accordion__item | Item |
.iu-accordion__trigger | Button trigger |
.iu-accordion__panel | Collapsible panel |
.iu-accordion__body-inner | Inner padding wrapper |
[data-iu-accordion-mode="single"] | Only one open at a time |
Pagination
Pagination với ellipsis tự động và keyboard navigation. Có thể render động qua JS API hoặc dùng markup tĩnh.
- …
- …
<ul class="iu-pagination">
<li class="iu-pagination__item">
<button class="iu-pagination__link iu-pagination__link--prev" data-iu-page="4">‹</button>
</li>
<li class="iu-pagination__item">
<button class="iu-pagination__link" data-iu-page="5" aria-current="page">5</button>
</li>
<li class="iu-pagination__item">
<button class="iu-pagination__link iu-pagination__link--next" data-iu-page="6">›</button>
</li>
</ul>
JavaScript API
InitUI.pagination.render("#pagination", {
totalPages: 10,
currentPage: 5,
siblingCount: 1,
onChange: function(page) { console.log(page); }
});
Class Reference
| Class | Mô tả |
|---|---|
.iu-pagination | List wrapper |
.iu-pagination__link | Page button |
[data-iu-page] | Page number / prev / next |
.iu-pagination--sm / --lg | Size variants |
File Input
Input file với drag & drop, hiển thị tên file dạng chip. Tự động xử lý qua init-ui.js.
<div class="iu-file" data-iu-file>
<input type="file" class="iu-file__input" id="file" multiple />
<label for="file" class="iu-file__dropzone">
<span class="iu-file__icon">📎</span>
<span class="iu-file__text"><strong>Click to upload</strong> or drag & drop</span>
</label>
<div class="iu-file__filenames"></div>
</div>
JavaScript API
// Listen for file changes
document.addEventListener("iu:file-change", function(e) {
console.log(e.detail.files);
});
Class Reference
| Class | Mô tả |
|---|---|
.iu-file | Wrapper |
.iu-file__input | Native file input |
.iu-file__dropzone | Visual drop zone |
.iu-file__filenames | Chip container |
Range Slider
Slider với gradient fill đồng bộ theo giá trị và output trực tiếp. Tự động init qua init-ui.js.
<input type="range" class="iu-range" min="0" max="100" value="65"
data-iu-range-output="#rangeOutput" />
<span id="rangeOutput">65</span>
JavaScript API
InitUI.range.sync(document.querySelector(".iu-range"));
Validation
Validation tự động cho input có data-iu-validate, sử dụng Constraint Validation API. Hiển thị trạng thái valid/invalid với border và message.
<div class="iu-field">
<input type="email" class="iu-input" data-iu-validate required />
<span class="iu-valid-feedback">Valid</span>
<span class="iu-invalid-feedback">Invalid</span>
</div>
JavaScript API
InitUI.validation.validate(document.querySelector("#myInput"));
Class Reference
| Class | Mô tả |
|---|---|
[data-iu-validate] | Opt-in validation trigger |
.iu-is-valid | Valid state border |
.iu-is-invalid | Invalid state border |
.iu-valid-feedback | Success message |
.iu-invalid-feedback | Error message |
Spacing
Utilities cho margin và padding theo spacing scale (4px base). Pattern: .iu-{m|p}{t|r|b|l|x|y}-{0..16}.
| Pattern | Example | Meaning |
|---|---|---|
.iu-m-{n} | .iu-m-4 | margin: 1rem |
.iu-mt-{n} | .iu-mt-6 | margin-top: 1.5rem |
.iu-mx-{n} | .iu-mx-4 | margin-left + margin-right |
.iu-my-{n} | .iu-my-8 | margin-top + margin-bottom |
.iu-p-{n} | .iu-p-4 | padding: 1rem |
.iu-px-{n} | .iu-px-6 | padding-left + padding-right |
.iu-gap-{n} | .iu-gap-4 | Set --iu-gap cho Stack/Cluster/Grid |
.iu-mx-auto | .iu-mx-auto | margin-inline: auto |
Giá trị hỗ trợ: 0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 16.
Text Utilities
Size, weight, alignment, color, và truncate.
.iu-text-xs
.iu-text-sm
.iu-text-base
.iu-text-lg
.iu-text-xl
.iu-text-2xl
.iu-text-3xl
.iu-truncate — Đoạn text rất dài sẽ bị cắt ngang và hiện dấu ba chấm.
<p class="iu-text-lg iu-font-semibold iu-text-primary">Heading</p>
<p class="iu-text-muted iu-truncate">Long text...</p>
Shadow
5 mức độ bóng được tint bằng primary hue thay vì đen phẳng.
<div class="iu-shadow-sm">...</div>
<div class="iu-shadow-md">...</div>
<div class="iu-shadow-lg">...</div>
<div class="iu-shadow-xl">...</div>
Gradient
Gradient tokens và utility class cho background + text.
<div class="iu-bg-gradient-primary">...</div>
<span class="iu-text-gradient">Gradient text</span>
Radius
Border-radius utilities.
<div class="iu-rounded-sm">...</div>
<div class="iu-rounded-md">...</div>
<div class="iu-rounded-lg">...</div>
<div class="iu-rounded-xl">...</div>
<div class="iu-rounded-full">...</div>
Overflow
| Class | CSS |
|---|---|
.iu-overflow-auto | overflow: auto |
.iu-overflow-hidden | overflow: hidden |
.iu-overflow-visible | overflow: visible |
.iu-overflow-x-auto | overflow-x: auto |
.iu-overflow-y-auto | overflow-y: auto |
Scrollbar
Style thanh cuộn theme-aware, hoặc ẩn hoàn toàn.
| Class | Mô tả |
|---|---|
.iu-scrollbar | Thanh cuộn custom, theme-aware |
.iu-scrollbar-hidden | Thanh cuộn mỏng (6px) |
.iu-scrollbar-hidden | Ẩn thanh cuộn (content vẫn scroll) |
Color Tokens
Toàn bộ palette được sinh từ oklch(from var(--iu-*-base) ...). Mỗi palette có 11 sắc độ (50→950) và cặp contrast tương ứng.
Primary
Semantic Aliases
| Token | Mặc định | Dark |
|---|---|---|
--iu-color-bg | neutral-0 | neutral-950 |
--iu-color-surface | neutral-0 | neutral-900 |
--iu-color-text | neutral-900 | neutral-50 |
--iu-color-text-muted | neutral-600 | neutral-400 |
--iu-color-border | neutral-200 | neutral-800 |
--iu-color-link | primary-600 | primary-400 |
--iu-focus-ring | primary-500 | primary-400 |
Typography Tokens
| Token | Giá trị |
|---|---|
--iu-font-sans | Inter, ui-sans-serif, system-ui, ... |
--iu-font-mono | JetBrains Mono, ui-monospace, ... |
--iu-fs-xs | 0.75rem |
--iu-fs-sm | 0.875rem |
--iu-fs-base | 1rem |
--iu-fs-lg | 1.125rem |
--iu-fs-xl | 1.25rem |
--iu-fs-2xl | 1.5rem |
--iu-fs-3xl | 1.875rem |
--iu-fs-4xl | 2.25rem |
--iu-fs-5xl | 3rem |
--iu-fw-normal..bold | 400 / 500 / 600 / 700 |
--iu-lh-tight | 1.2 |
--iu-lh-normal | 1.5 |
--iu-lh-relaxed | 1.7 |
Spacing Tokens
Scale 4px base. Sử dụng cho margin, padding, gap.
| Token | Giá trị |
|---|---|
--iu-space-1 | 0.25rem (4px) |
--iu-space-2 | 0.5rem (8px) |
--iu-space-3 | 0.75rem (12px) |
--iu-space-4 | 1rem (16px) |
--iu-space-5 | 1.25rem (20px) |
--iu-space-6 | 1.5rem (24px) |
--iu-space-8 | 2rem (32px) |
--iu-space-10 | 2.5rem (40px) |
--iu-space-12 | 3rem (48px) |
--iu-space-16 | 4rem (64px) |
--iu-space-20 | 5rem (80px) |
--iu-space-24 | 6rem (96px) |
Radius Tokens
| Token | Giá trị |
|---|---|
--iu-radius-sm | 0.25rem |
--iu-radius-md | 0.5rem |
--iu-radius-lg | 0.875rem |
--iu-radius-xl | 1.25rem |
--iu-radius-full | 9999px |
Shadow Tokens
Bóng được tint bằng màu primary hue thay vì đen phẳng, tạo cảm giác ấm và đồng bộ với theme.
| Token | Mô tả |
|---|---|
--iu-shadow-sm | 0 1px 2px hsl(... / 0.06) |
--iu-shadow-md | 0 4px 12px + 0 2px 4px |
--iu-shadow-lg | 0 12px 32px + 0 4px 8px |
--iu-shadow-xl | 0 24px 64px hsl(... / 0.16) |
--iu-ring | Focus ring 3px, 35% opacity |
Motion Tokens
| Token | Giá trị |
|---|---|
--iu-ease | cubic-bezier(0.4, 0, 0.2, 1) |
--iu-ease-out | cubic-bezier(0, 0, 0.2, 1) |
--iu-ease-spring | cubic-bezier(0.34, 1.56, 0.64, 1) |
--iu-duration-fast | 120ms |
--iu-duration-base | 200ms |
--iu-duration-slow | 320ms |
Z-Index Tokens
| Token | Giá trị |
|---|---|
--iu-z-dropdown | 1000 |
--iu-z-sticky | 1100 |
--iu-z-overlay | 1200 |
--iu-z-modal | 1300 |
--iu-z-toast | 1400 |
--iu-z-tooltip | 1500 |
Eyebrow
Label nhỏ kiểu monospace cho section header — tạo cảm giác technical/documentation.
<span class="iu-eyebrow">01 · Components</span>
Notched Corner
Góc cắt chéo thay vì bo tròn — điểm nhấn thương hiệu opt-in. Dùng kèm với button hoặc card.
<button class="iu-btn iu-btn--primary iu-notched iu-notched--lg">...</button>
Dashed Focus
Focus ring dạng dashed thay vì glow mềm. Bật toàn cục bằng <html data-iu-focus="dashed"> hoặc scoped vào subtree.
<html data-iu-focus="dashed">
<button>Focus ring dashed</button>
</html>
Noise Texture
Lớp grain overlay tinh tế cho hero sections. Không nên dùng trên element tương tác nhỏ.
Surface có noise texture overlay
<div class="iu-texture-noise iu-bg-gradient-primary-soft">...</div>