Skip to content

Introduction ​

thl-ui is a framework‑agnostic design system with its own CSS (no Bootstrap, no jQuery) that ships native components for React, Vue and Angular.

Architecture ​

            ┌────────────────────────── @thl-ui/core ──────────────────────────┐
            │  createThl()  →  config store · i18n · applyToDocument()          │
            │  headless: tabs · table · select · toast · upload · calendar …    │
            │  utils: bem() · cx() · focusTrap · scrollLock · clickOutside      │
            └───────────────▲──────────────────▲──────────────────▲────────────┘
                            │                  │                  │
   @thl-ui/tokens ──► @thl-ui/styles (CSS vars, .thl-* BEM, 12 skins, dark)
                            │                  │                  │
                  @thl-ui/react         @thl-ui/vue        @thl-ui/angular
               ThlProvider + hooks   plugin + composables  provideThlUI + signals
PackagePurpose
@thl-ui/tokensDesign tokens (palette, spacing, radius, skins) → CSS custom properties
@thl-ui/stylesFramework‑free CSS (thl-ui.css, per‑component CSS, SCSS sources)
@thl-ui/localesMessages for en, ja, vi, zh + types
@thl-ui/coreConfig, i18n, headless state machines, utilities
@thl-ui/iconsIcon registry (lucide subset, extendable with font icons)
@thl-ui/chartsDependency‑free SVG chart geometry
@thl-ui/react · @thl-ui/vue · @thl-ui/angularNative adapters

Same API, three frameworks ​

Every adapter renders identical markup (built with the shared bem() helper) and exposes the same prop names, so a component looks and behaves the same everywhere:

vue
<ThlButton variant="primary" icon="download" rounded>Download</ThlButton>
tsx
<Button variant="primary" icon="download" rounded>Download</Button>
html
<button thl-button variant="primary" icon="download" rounded>Download</button>

Differences follow each framework's idioms only:

ConceptVueReactAngular
Installapp.use(ThlUI, config)<ThlProvider config>provideThlUI(config)
Two‑way bindingv-modelvalue + onChange[(value)], formControlName, ngModel
TranslateuseI18n().t / $tuseT()ThlI18nService.t / | thlT
ConfiguseThlConfig()useThlConfig()ThlConfigService
ToastuseToast()useToast()ThlToastService
Confirmconfirm()confirm()ThlModalService.confirm()
Component namesThlButtonButtonThlButtonComponent / thl-* selectors

Next steps ​