Theming
Four override layers, from global tokens down to a single component.
The model
No component hard-codes a color; every visual reads a CSS custom property, so re-theming is a stylesheet change. The four layers run widest first. Pick the narrowest one that solves the problem.
| Layer | Where it lives | Scope |
|---|---|---|
| Global tokens | :root in base.css | Everything |
| Theme selectors | [data-theme='dark'], [data-tx-contrast='high'] | A whole mode |
| BUI tokens | --tx-bui-* | The AI suite |
| Component hooks | --tx-<component>-* | One component, or one subtree |
The token inventory is in Design Foundations.
Global tokens
Redefine tokens after importing base.css. Components resolve them at paint time, so an override applies to the whole subtree below it.
@import '@talex-touch/tuffex/base.css';
:root {
--tx-color-primary: #7c5cff;
--tx-border-radius-base: 8px;
--tx-transition-duration: 0.24s;
}
--tx-color-primary-soft and --tx-coloring-border-color are color-mix() expressions on --tx-color-primary, so they follow it. The primary ramp (--tx-color-primary-light-*, --tx-color-primary-dark-2) is fixed hex, and the default focus ring reads from it; override the ramp too when rebranding.
Dark mode
Dark is a selector, not a media query: set data-theme="dark" or the dark class on any ancestor.
<html data-theme="dark">
<!-- or -->
<html class="dark">
- The two are equivalent, so Tuffex drops into a Tailwind app (
.dark) or adata-themeapp without an adapter. - Set either on a subtree to get a dark island on a light page.
High contrast
A fourth palette that raises text and border contrast in light and dark.
| Trigger | Effect |
|---|---|
html[data-tx-contrast='high'] or html.contrast | On, explicitly |
@media (prefers-contrast: more) | On, following the OS |
html[data-tx-contrast='normal'] | Opts out of the media query |
With data-theme="dark" and either high-contrast trigger, the dark high-contrast palette applies; the two themes don't stack.
AI suite tokens
--tx-bui-* came over with the Beautiful UI components (surface, inset, field, ink, and accent / green / orange / red with matching tints) and has its own dark block under the same [data-theme='dark'] / .dark selectors. Override it when AI surfaces shouldn't inherit your brand hue:
:root {
--tx-bui-accent: #7c5cff;
--tx-bui-accent-tint: #f0ecff;
}
Component hooks
--tx-<component>-* restyles one component without touching the global palette. Names are predictable (--tx-collapse-header-bg, --tx-avatar-ring-color, --tx-progress-height), and each has a fallback. They inherit, so setting them on a wrapper themes that subtree only.
<template>
<section class="settings-panel">
<TxCollapse v-model="open">
<TxCollapseItem title="Appearance" name="appearance">…</TxCollapseItem>
</TxCollapse>
</section>
</template>
<style scoped>
.settings-panel {
--tx-collapse-radius: 6px;
--tx-collapse-header-bg: transparent;
--tx-collapse-border: rgba(148, 163, 184, 0.24);
}
</style>
Each component page lists the hooks it reads. Use them instead of descendant selectors into component internals: custom properties are the supported surface, class names are not.
Caveats
- When a component exposes a fill hook, set the token, not
background-color: some fills arebackground-imagegradients, andbackground-colorpaints behind them. - Import
base.cssexactly once. With two copies, the one that loads last wins, which is rarely the one you edited.
Technologies
- Tokens and theme selectors:
packages/tuffex/packages/components/style/variables.scss. - AI suite tokens:
packages/tuffex/packages/components/style/bui-tokens.scss. - Runtime entry:
@talex-touch/tuffex/base.css.