Global config
All three adapters are driven by one config object, created by createThl() in @thl-ui/core. You pass it to ThlProvider (React), app.use(ThlUI, …) (Vue) or provideThlUI(…) (Angular).
Options
| Option | Type | Default | Description |
|---|---|---|---|
prefix | string | 'thl' | CSS class and custom-property prefix (.thl-btn, --thl-theme) |
theme | ThlSkin | 'default' | One of 12 skins: default · green · yellow · red · purple · black and each with -dark (dark sidebar) |
colorMode | 'light' | 'dark' | 'auto' | 'light' | auto follows prefers-color-scheme live |
layout | 'vertical' | 'mini' | 'horizontal' | 'vertical' | AppLayout variant |
fixedHeader | boolean | true | Sticky topbar |
fixedSidebar | boolean | true | Sticky sidebar |
size | 'sm' | 'md' | 'lg' | 'md' | Base font size and control height |
radius | 'sharp' | 'rounded' | 'rounded' | sharp sets all radius tokens to 0 |
zIndex | number | 1000 | Overlay base: dropdown = base, modal = base + 50, toast = base + 80 |
locale | string | 'en' | Active locale |
fallbackLocale | string | 'en' | Used when a key is missing |
locales | string[] | ['en','vi','ja','zh'] | Offered in the language switcher |
messages | Record<locale, Messages> | {} | Extra / override messages, deep-merged with built-ins |
loadLocale | (l) => Promise<Messages> | — | Lazy loader for locales not bundled |
components | Partial<ThlComponentDefaults> | see below | Per-component default props |
persist | boolean | { key } | false | Save theme / colorMode / locale / layout / fixed* / size / radius to localStorage (key thl-ui-config) |
root | HTMLElement | <html> | Element that receives the data-thl-* attributes |
icons | IconRegistry | — | Register extra icons (adapter option) |
What happens at runtime
createThl() writes the config to the root element as data attributes. All styling reacts to these attributes, so changing config never re-renders components unnecessarily:
<html lang="vi" dir="ltr"
data-thl-theme="green-dark" data-thl-color-mode="dark" data-thl-layout="vertical"
data-thl-size="md" data-thl-radius="rounded" data-thl-fixed-header data-thl-fixed-sidebar>Changing config at runtime
<script setup lang="ts">
import { useThlConfig } from '@thl-ui/vue';
const { config, set } = useThlConfig();
</script>
<template>
<ThlButton @click="set({ theme: 'purple', colorMode: 'dark' })">Purple · dark</ThlButton>
<p>Layout: {{ config.layout }}</p>
</template>import { useThlConfig, Button } from '@thl-ui/react';
const [config, set] = useThlConfig();
<Button onClick={() => set({ theme: 'purple', colorMode: 'dark' })}>Purple · dark</Button>import { ThlConfigService } from '@thl-ui/angular';
readonly cfg = inject(ThlConfigService);
// template: {{ cfg.config().layout }}
toPurple() { this.cfg.set({ theme: 'purple', colorMode: 'dark' }); }The <SettingsPanel> (built into AppLayout) is just a UI for these same set() calls.
Component defaults
components sets default props for every instance. Explicit props always win:
createThl({
components: {
Button: { rounded: true, size: 'sm' },
Table: { pageSize: 25, pageSizes: [25, 50, 100], striped: true },
Toast: { position: 'bottom-right', duration: 5000, max: 3 },
Modal: { closeOnBackdrop: false, centered: true },
Pagination: { maxPages: 5 },
Sidebar: { breakpoint: 1024 },
},
});Built-in defaults:
{
Toast: { position: 'top-right', duration: 3500, max: 5 },
Table: { pageSize: 10, pageSizes: [10, 25, 50, 100], hover: true },
Modal: { closeOnBackdrop: true, closeOnEsc: true },
Pagination: { maxPages: 7 },
Sidebar: { breakpoint: 1170 },
}The type ThlComponentDefaults is extensible through declaration merging:
declare module '@thl-ui/core' {
interface ThlComponentDefaults {
MyWidget: { dense?: boolean };
}
}Sharing one instance
Create the instance yourself to share it with non-UI code (stores, services, micro-frontends):
import { createThl } from '@thl-ui/core';
export const thl = createThl({ locale: 'en', persist: true });
thl.subscribe((c, prev) => { if (c.locale !== prev.locale) api.setLanguage(c.locale); });
thl.t('common.save'); // "Lưu"<ThlProvider instance={thl}>…</ThlProvider> // React
app.use(ThlUI, { instance: thl }); // Vue
provideThlUI({ instance: thl }); // AngularThlInstance API: get(), set(patch), subscribe(fn), defaults(name, props), t(), setLocale(), resolvedColorMode(), applyToDocument(), attach(), destroy(), plus config (store) and i18n.