Skip to main content
Init UI v0.2.0
Init UI v0.2.0

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

HTML
<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.cssinit-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 đủ:

Chrome / Edge111+
Safari15.4+
Firefox128+

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.

index.html
<!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.

JS
// 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:

custom.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ĩaMặc định
--iu-primary-baseMàu chủ đạo — CTA, link, focusoklch(58% 0.135 165)
--iu-neutral-baseXám nền, text, borderoklch(50% 0.006 165)
--iu-success-baseTrạng thái thành côngoklch(55% 0.14 150)
--iu-danger-baseTrạng thái lỗi, nguy hiểmoklch(55% 0.19 25)
--iu-warning-baseTrạng thái cảnh báooklch(70% 0.15 80)
--iu-info-baseThông tin, trung tính-xanhoklch(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.

Badge
Card text

Semantic Aliases

Nếu bạn cần điều chỉnh sâu hơn, ghi đè các alias ngữ nghĩa:

custom.css
: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ế độ:

<button class="iu-btn iu-btn--secondary" data-iu-theme-toggle>Toggle Theme</button>

JavaScript API

JS
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:

<head>
<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".

UI & System (39)
initui
spinner
check
danger
warning
info
close
sun
moon
eye
eye-off
menu
search
arrow-top
chevron-down
chevron-up
chevron-left
chevron-right
plus
minus
trash
pencil
copy
external-link
bell
user
calendar
mail
download
upload
lock
log-out
filter
arrow-right
check-circle
x-circle
dots-horizontal
star
heart
Social & Brand (9)
facebook
twitter
instagram
linkedin
github
youtube
tiktok
telegram
discord

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:

JS
InitUI.icon.add("rocket", '<svg viewBox="0 0 24 24" fill="currentColor" width="100%" height="100%"><path d="..."/></svg>');
HTML
<span class="iu-icon" data-icon="rocket"></span>
Nén SVG trước khi thêm vào code
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

MethodMô 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ể:

Default container
Small container
<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.

1
2
3
<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:

Auto
Fit
Grid
Columns
<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:

.iu-col-2
auto
auto
<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.

Item 1
Item 2
Item 3
<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.

Design Dev Docs Beta
<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:

ClassCSS
.iu-flexdisplay: flex
.iu-flex-colflex-direction: column
.iu-flex-wrapflex-wrap: wrap
.iu-items-centeralign-items: center
.iu-justify-betweenjustify-content: space-between
.iu-growflex-grow: 1
.iu-shrink-0flex-shrink: 0

Button

Button component với 6 variant chính và 3 kích thước. Tất cả đều có hover, active, và focus-visible states.

Variants

<div class="iu-cluster" style="--iu-gap:0.75rem;">
  <button class="iu-btn iu-btn--primary">Primary</button>
  <button class="iu-btn iu-btn--secondary">Secondary</button>
  <button class="iu-btn iu-btn--outline">Outline</button>
  <button class="iu-btn iu-btn--ghost">Ghost</button>
  <button class="iu-btn iu-btn--danger">Danger</button>
  <button class="iu-btn iu-btn--gradient">Gradient</button>
</div>

Kích thước

<div class="iu-cluster" style="--iu-gap:0.75rem;">
  <button class="iu-btn iu-btn--primary iu-btn--sm">Small</button>
  <button class="iu-btn iu-btn--primary">Base</button>
  <button class="iu-btn iu-btn--primary iu-btn--lg">Large</button>
</div>

Trạng thái

<div class="iu-cluster" style="--iu-gap:0.75rem;">
  <button class="iu-btn iu-btn--primary" disabled>Disabled</button>
  <button class="iu-btn iu-btn--primary iu-btn--icon" aria-label="Settings">
    <span class="iu-icon" data-icon="search"></span>
  </button>
  <button class="iu-btn iu-btn--primary iu-btn--block" style="max-width:200px;">Block</button>
</div>

Class Reference

ClassMô tả
.iu-btnBase button
.iu-btn--primaryNền primary, chữ trắng
.iu-btn--secondaryNền subtle, viền nhẹ
.iu-btn--outlineTrong suốt, viền primary
.iu-btn--ghostTrong suốt, không viền
.iu-btn--dangerNền danger đỏ
.iu-btn--gradientGradient primary
.iu-btn--sm / --lgKích thước nhỏ / lớn
.iu-btn--blockChiếm full width
.iu-btn--iconHình vuông, chỉ chứa icon

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

ClassMô tả
.iu-cardBase card
.iu-card--hoverHiệu ứng nâng khi hover
.iu-card--gradientNền gradient soft
.iu-card__bodyPadding nội dung
.iu-card__titleTiêu đề card
.iu-card__textMô tả card (muted)
.iu-card__footerVùng footer có border-top
.iu-card__mediaChứ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.

Primary Success Danger Warning Info Online
<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

Solid
<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.

Thành công!
Đã lưu thay đổi.
Chú ý
Phiên bản đang thử nghiệm.
Lỗi
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

Email không hợp lệ.
<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

ClassMô tả
.iu-fieldWrapper label + input + hint
.iu-labelLabel form
.iu-inputText input
.iu-selectSelect dropdown (custom arrow)
.iu-textareaTextarea (resize: vertical)
.iu-hintHelper text dưới input
.iu-input--iconInput 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 inputbutton.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.

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

JS
InitUI.offcanvas.open("docsOffcanvas");
InitUI.offcanvas.close("docsOffcanvas");

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

JS
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

68% hoàn thành
<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

ClassMô tả
.iu-progressBar container
.iu-progress__barThanh tiến độ (set --iu-progress-value)
.iu-progress__bar--gradientGradient fill
.iu-progress--indeterminateAnimation vô hạn
.iu-progress--sm / --lgKích thước
.iu-progress-ringVò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.

H HN 🌱
<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.

ComponentTrạng tháiTừ bản
ButtonỔn địnhv0.1.0
CardỔn địnhv0.1.0
ToastỔn địnhv0.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:

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

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

JS
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

JS
InitUI.accordion.toggle(item);   // Toggle one item
InitUI.accordion.collapseAll();  // Close all items

Class Reference

ClassMô tả
.iu-accordionWrapper
.iu-accordion__itemItem
.iu-accordion__triggerButton trigger
.iu-accordion__panelCollapsible panel
.iu-accordion__body-innerInner 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

JS
InitUI.pagination.render("#pagination", {
  totalPages: 10,
  currentPage: 5,
  siblingCount: 1,
  onChange: function(page) { console.log(page); }
});

Class Reference

ClassMô tả
.iu-paginationList wrapper
.iu-pagination__linkPage button
[data-iu-page]Page number / prev / next
.iu-pagination--sm / --lgSize variants

Button Loading

Thêm trạng thái loading cho button với spinner và disabled tự động. Dùng InitUI.button.setLoading() hoặc data-iu-loading-on-submit cho form.

<button class="iu-btn iu-btn--primary" onclick="InitUI.button.setLoading(this, true)">
  Submit
</button>

<!-- Auto on form submit -->
<form data-iu-loading-on-submit>
  <button type="submit">Save</button>
</form>

JavaScript API

JS
InitUI.button.setLoading("#btn", true);  // Start loading
InitUI.button.setLoading("#btn", false); // Stop loading

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

JS
// Listen for file changes
document.addEventListener("iu:file-change", function(e) {
  console.log(e.detail.files);
});

Class Reference

ClassMô tả
.iu-fileWrapper
.iu-file__inputNative file input
.iu-file__dropzoneVisual drop zone
.iu-file__filenamesChip 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.

Giá trị: 65%
<input type="range" class="iu-range" min="0" max="100" value="65"
       data-iu-range-output="#rangeOutput" />
<span id="rangeOutput">65</span>

JavaScript API

JS
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.

Email hợp lệ Vui lòng nhập email đúng định dạng
Mã phải có đúng 6 chữ số
<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

JS
InitUI.validation.validate(document.querySelector("#myInput"));

Class Reference

ClassMô tả
[data-iu-validate]Opt-in validation trigger
.iu-is-validValid state border
.iu-is-invalidInvalid state border
.iu-valid-feedbackSuccess message
.iu-invalid-feedbackError message

Spacing

Utilities cho margin và padding theo spacing scale (4px base). Pattern: .iu-{m|p}{t|r|b|l|x|y}-{0..16}.

PatternExampleMeaning
.iu-m-{n}.iu-m-4margin: 1rem
.iu-mt-{n}.iu-mt-6margin-top: 1.5rem
.iu-mx-{n}.iu-mx-4margin-left + margin-right
.iu-my-{n}.iu-my-8margin-top + margin-bottom
.iu-p-{n}.iu-p-4padding: 1rem
.iu-px-{n}.iu-px-6padding-left + padding-right
.iu-gap-{n}.iu-gap-4Set --iu-gap cho Stack/Cluster/Grid
.iu-mx-auto.iu-mx-automargin-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

Normal Medium Semibold Bold
Muted Subtle Primary Success Danger Warning

.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.

sm
md
lg
xl
<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.

primary
success
danger
info
warning
Text Gradient
<div class="iu-bg-gradient-primary">...</div>
<span class="iu-text-gradient">Gradient text</span>

Radius

Border-radius utilities.

sm
md
lg
xl
full
<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

ClassCSS
.iu-overflow-autooverflow: auto
.iu-overflow-hiddenoverflow: hidden
.iu-overflow-visibleoverflow: visible
.iu-overflow-x-autooverflow-x: auto
.iu-overflow-y-autooverflow-y: auto

Scrollbar

Style thanh cuộn theme-aware, hoặc ẩn hoàn toàn.

ClassMô tả
.iu-scrollbarThanh cuộn custom, theme-aware
.iu-scrollbar-hiddenThanh 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

--iu-primary-50
--iu-primary-100
--iu-primary-200
--iu-primary-300
--iu-primary-400
--iu-primary-500
--iu-primary-600
--iu-primary-700
--iu-primary-800
--iu-primary-900
--iu-primary-950

Semantic Aliases

TokenMặc địnhDark
--iu-color-bgneutral-0neutral-950
--iu-color-surfaceneutral-0neutral-900
--iu-color-textneutral-900neutral-50
--iu-color-text-mutedneutral-600neutral-400
--iu-color-borderneutral-200neutral-800
--iu-color-linkprimary-600primary-400
--iu-focus-ringprimary-500primary-400

Typography Tokens

TokenGiá trị
--iu-font-sansInter, ui-sans-serif, system-ui, ...
--iu-font-monoJetBrains Mono, ui-monospace, ...
--iu-fs-xs0.75rem
--iu-fs-sm0.875rem
--iu-fs-base1rem
--iu-fs-lg1.125rem
--iu-fs-xl1.25rem
--iu-fs-2xl1.5rem
--iu-fs-3xl1.875rem
--iu-fs-4xl2.25rem
--iu-fs-5xl3rem
--iu-fw-normal..bold400 / 500 / 600 / 700
--iu-lh-tight1.2
--iu-lh-normal1.5
--iu-lh-relaxed1.7

Spacing Tokens

Scale 4px base. Sử dụng cho margin, padding, gap.

TokenGiá trị
--iu-space-10.25rem (4px)
--iu-space-20.5rem (8px)
--iu-space-30.75rem (12px)
--iu-space-41rem (16px)
--iu-space-51.25rem (20px)
--iu-space-61.5rem (24px)
--iu-space-82rem (32px)
--iu-space-102.5rem (40px)
--iu-space-123rem (48px)
--iu-space-164rem (64px)
--iu-space-205rem (80px)
--iu-space-246rem (96px)

Radius Tokens

TokenGiá trị
--iu-radius-sm0.25rem
--iu-radius-md0.5rem
--iu-radius-lg0.875rem
--iu-radius-xl1.25rem
--iu-radius-full9999px

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.

TokenMô tả
--iu-shadow-sm0 1px 2px hsl(... / 0.06)
--iu-shadow-md0 4px 12px + 0 2px 4px
--iu-shadow-lg0 12px 32px + 0 4px 8px
--iu-shadow-xl0 24px 64px hsl(... / 0.16)
--iu-ringFocus ring 3px, 35% opacity

Motion Tokens

TokenGiá trị
--iu-easecubic-bezier(0.4, 0, 0.2, 1)
--iu-ease-outcubic-bezier(0, 0, 0.2, 1)
--iu-ease-springcubic-bezier(0.34, 1.56, 0.64, 1)
--iu-duration-fast120ms
--iu-duration-base200ms
--iu-duration-slow320ms

Z-Index Tokens

TokenGiá trị
--iu-z-dropdown1000
--iu-z-sticky1100
--iu-z-overlay1200
--iu-z-modal1300
--iu-z-toast1400
--iu-z-tooltip1500

Eyebrow

Label nhỏ kiểu monospace cho section header — tạo cảm giác technical/documentation.

01 · Components
<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>