Components/Theming

Theming

The four layers you can override, from global tokens down to a single component

Since 0.4.0BETA

This component doc is in progress

This page is still being migrated. Demos and API details may change.

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.

LayerWhere it livesScope
Global tokens:root in base.cssEverything
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.

EXAMPLE.CSS
@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:

EXAMPLE.HTML
<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:

TriggerEffect
html[data-tx-contrast='high'] or html.contrastHigh 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:

EXAMPLE.CSS
: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:

EXAMPLE.VUE
<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 are background-image gradients, and a background-color override paints behind them.
  • Import base.css exactly 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.