Theming
The four layers you can override, from global tokens down to a single component
The model
No Tuffex component hard-codes a colour. Every visual reads a CSS custom property, which means re-theming is a stylesheet change and never a fork. The properties come in four layers, widest first — pick the narrowest one that solves your 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 itself — the typography scale and the full colour ramp — is documented in Design Foundations. This page is about overriding it.
Global tokens
Redefine any token after importing base.css. Because the components resolve them at paint time, an override anywhere up the tree wins for everything below it.
@import '@talex-touch/tuffex/base.css';
:root {
--tx-color-primary: #7c5cff;
--tx-border-radius-base: 8px;
--tx-transition-duration: 0.24s;
}
Overriding --tx-color-primary is usually enough to rebrand: the derived tokens (--tx-color-primary-soft, --tx-coloring-border-color, --tx-focus-ring-shadow) are color-mix() expressions built on it, so they follow.
Dark mode
Dark is a selector, not a media query — the app decides when it applies. Set either data-theme="dark" or the dark class on any ancestor:
<html data-theme="dark">
<!-- or -->
<html class="dark">
Both selectors are equivalent, which is what lets Tuffex drop into a Tailwind app (.dark) and a data-theme app without an adapter. Since they are ordinary selectors, scoping one to a subtree gives you a dark island on a light page.
High contrast
Tuffex ships a fourth palette that raises text and border contrast in both light and dark. It turns on three ways:
| Trigger | Effect |
|---|---|
html[data-tx-contrast='high'] or html.contrast | High contrast, explicitly |
@media (prefers-contrast: more) | High contrast automatically |
html[data-tx-contrast='normal'] | Opts out of the media query |
The pairing matters: the OS preference is honoured by default, and data-tx-contrast="normal" is the escape hatch for an app that wants to override the system. Combining data-theme="dark" with either high-contrast trigger selects the dark high-contrast palette rather than layering two themes.
AI suite tokens
The AI suite carries its own --tx-bui-* layer — surface, inset, field, ink, and the accent/green/orange/red families with matching tints — ported alongside the Beautiful UI components so their density and hairline system stays intact. It has its own dark block under the same [data-theme='dark'] / .dark selectors, so a dark toggle moves both layers together. Retheme it separately when the AI surfaces should not inherit your brand hue:
:root {
--tx-bui-accent: #7c5cff;
--tx-bui-accent-tint: #f0ecff;
}
Component hooks
Around three hundred --tx-<component>-* properties let one component be restyled without touching the global palette. They follow a predictable shape — --tx-collapse-header-bg, --tx-avatar-ring-color, --tx-progress-height — and each is declared with a fallback, so setting none of them is always valid.
Because they are inherited custom properties, 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. Prefer these over descendant selectors into component internals: the custom properties are the supported surface, the class names are not.
Notes
- Set tokens, not
background-color, when a component already exposes a fill hook. Some fills arebackground-imagegradients, and abackground-coloroverride paints behind them. - Import
base.cssexactly once. Two copies mean whichever loads last wins, which is rarely the one you edited.
Source
- Token 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.