Hỏi đáp & xử lý sự cố
Cài đặt
Giao diện không có màu, chữ font hệ thống
Bạn chưa import CSS. Thêm một lần ở điểm khởi động app:
import '@thl-ui/styles/thl-ui.css';Angular: thêm node_modules/@thl-ui/styles/dist/thl-ui.css vào styles trong angular.json. Và thêm class thl-body vào <body> để có font và màu nền.
npm install báo lỗi peer dependency
thl-ui cần Vue ≥ 3.5.2, React ≥ 18 hoặc Angular ≥ 20. Bản thấp hơn không được hỗ trợ: Angular 19 không biên dịch được thư viện, Vue < 3.5.2 báo lỗi kiểu TypeScript. Nâng framework lên, hoặc nếu bắt buộc thì cài bằng --legacy-peer-deps (không khuyến khích).
TypeScript báo không tìm thấy kiểu của component
Dùng "moduleResolution": "Bundler" (hoặc "NodeNext") trong tsconfig.json. Chế độ "node" cũ không đọc được trường exports của package.
Có cần cài Bootstrap, jQuery hay font Google không?
Không. CSS của thl-ui tự viết hoàn toàn, font Open Sans được đóng gói sẵn trong @thl-ui/styles (tự host, không gọi ra ngoài).
Giao diện
Đổi màu thương hiệu
Ghi đè biến CSS sau khi import thl-ui.css:
:root {
--thl-theme: #7c3aed; /* màu nền của nút, tab đang chọn… */
--thl-on-theme: #fff; /* chữ đặt trên màu đó */
--thl-theme-text: #6d28d9; /* màu đó khi dùng làm chữ trên nền trắng */
}Giữ độ tương phản tối thiểu 4.5:1 giữa --thl-on-theme và --thl-theme, và giữa --thl-theme-text và nền trắng. Xem Theme & dark mode.
Chỉ đổi giao diện cho một vùng
<section data-thl-theme="red" data-thl-color-mode="dark">…</section>CSS của tôi bị CSS thư viện đè (hoặc ngược lại)
Mọi class đều có tiền tố thl-, và màu link mặc định có độ ưu tiên bằng 0 (:where(...)), nên một selector class bình thường của bạn sẽ thắng. Nếu muốn đổi tiền tố để tránh trùng: prefix: 'my' trong config và build lại SCSS với $prefix: my (@use "@thl-ui/styles/scss/index" with ($prefix: "my")).
Bundle quá lớn
- Vue: đừng dùng
app.use(ThlUI)mặc định (đăng ký mọi component). Dùngimport { ThlUI } from '@thl-ui/vue'cho phần cấu hình, rồi import từng component bạn cần. Chỉ dùng Button: ~120 KB thay vì ~230 KB. - React và Angular: import từng component; bundler tự bỏ phần không dùng.
- CSS theo từng component:
@thl-ui/styles/components/button.css… (nhớ thêm@thl-ui/styles/tokens.cssvà@thl-ui/styles/fonts.css).
Hành vi
Cài đặt người dùng (ngôn ngữ, skin, chế độ tối) không được nhớ
Bật persist: true trong config. Dữ liệu lưu ở localStorage khoá thl-ui-config (đổi tên khoá: persist: { key: 'my-app-ui' }). Lưu ý giá trị đã lưu sẽ thắng giá trị trong config ở lần tải sau.
Toast hoặc confirm() không hiện
AppLayout đã gắn sẵn chỗ hiển thị. Nếu bạn không dùng AppLayout, đặt một lần ở gốc app:
<ThlToaster />
<ThlConfirmHost />(React: <Toaster /> và <ConfirmHost />; Angular: <thl-toaster /> và <thl-confirm-host />.) Khi chưa có ConfirmHost, confirm() dùng tạm window.confirm của trình duyệt.
Menu bên trái tải lại cả trang khi bấm
Sidebar mặc định dùng <a href>. Truyền slot link (Vue), prop renderLink (React) hoặc template thlMenuLink (Angular) để dùng router link. Xem bước 3 trong Hướng dẫn.
Lỗi form không hiện
Lỗi chỉ hiện sau lần bấm Submit đầu tiên. Mỗi ThlField cần name, value và rules, và phải nằm trong ThlForm có :values. Muốn hiện lỗi từ server: truyền error="…" vào ThlField.
Thông báo lỗi kiểm tra vẫn là tiếng Anh
Thông báo lấy theo ngôn ngữ hiện tại. Kiểm tra locale trong config, hoặc giá trị đã lưu trong localStorage nếu bật persist. Ngôn ngữ chưa có bản dịch sẽ dùng fallbackLocale (mặc định en).
Thêm một ngôn ngữ mới
app.use(ThlUI, {
locales: ['vi', 'en', 'ko'],
messages: { ko: { common: { ok: '확인', cancel: '취소' } /* … */ } },
});Khoá nào chưa dịch sẽ lấy từ fallbackLocale. Ngôn ngữ viết từ phải sang trái (ar, he, fa, ur) tự đặt dir="rtl" và giao diện tự lật.
Khả năng tiếp cận
Nút chỉ có icon
Luôn truyền nhãn cho trình đọc màn hình:
<ThlButton icon="trash-2" aria-label="Xoá" />Ô nhập không có nhãn hiển thị
Bọc trong ThlField label="…" (nhãn tự gắn vào ô nhập), hoặc truyền aria-label.
Vẫn chưa được?
Mở playground tương ứng (npm run dev:vue / dev:react / dev:angular) và so với mã nguồn trang mẫu trong apps/playground-*: mọi component đều có ví dụ chạy được ở đó.