Skip to main content

Customization

Tosui exposes its design tokens as CSS custom properties. Override a token after importing the library styles to change every component that uses it.

Quick start​

Customize your brand colors for both light and dark modes in one place:

/* custom-theme.css */
:root {
/* Light mode primary - teal */
--t-light-primary-default: #0d9488;
--t-light-primary-emphasis: #0f766e;
--t-light-primary-subtle: #ccfbf1;

/* Dark mode primary - teal */
--t-dark-primary-default: #2dd4bf;
--t-dark-primary-emphasis: #5eead4;
--t-dark-primary-subtle: #134e4a;
}

Import after Tosui's styles:

import "@tosui/react/styles.css";
import "./custom-theme.css";

Tosui maps these primitive values to the active light or dark theme.

How theming works​

Tosui uses a two-tier variable system for colors:

  1. Primitive variables (--t-light-*, --t-dark-*) hold the actual color values for each mode
  2. Semantic variables (--t-color-*) reference the matching primitive for the active theme

For example, --t-color-primary-default automatically resolves to --t-light-primary-default in light mode and --t-dark-primary-default in dark mode.

When to use which​

Use caseVariable typeExample
Theme customization (both modes)Primitives--t-light-primary-default, --t-dark-primary-default
Scoped overridesSemantic--t-color-primary-default
Single element stylingSemantic--t-color-primary-default
Single-mode-only changesSemantic--t-color-primary-default

Use primitive variables to define a theme. Use semantic variables for a scoped override in the active theme.

Customizing colors​

Brand colors​

Primary and accent colors each have three variants:

VariantPurpose
-defaultStandard state (buttons, links)
-emphasisHover/active states
-subtleBackgrounds, badges
:root {
/* Primary brand color */
--t-light-primary-default: #8b5cf6;
--t-light-primary-emphasis: #7c3aed;
--t-light-primary-subtle: #ede9fe;

--t-dark-primary-default: #a78bfa;
--t-dark-primary-emphasis: #c4b5fd;
--t-dark-primary-subtle: #4c1d95;

/* Accent color */
--t-light-accent-default: #f59e0b;
--t-light-accent-emphasis: #d97706;
--t-light-accent-subtle: #fef3c7;

--t-dark-accent-default: #fbbf24;
--t-dark-accent-emphasis: #fcd34d;
--t-dark-accent-subtle: #78350f;
}

Feedback colors​

Success, warning, error, and info follow the same -default, -emphasis, -subtle pattern:

:root {
/* Example: custom error colors */
--t-light-error-default: #dc2626;
--t-light-error-emphasis: #b91c1c;
--t-light-error-subtle: #fee2e2;

--t-dark-error-default: #f87171;
--t-dark-error-emphasis: #fca5a5;
--t-dark-error-subtle: #7f1d1d;
}

Surface colors​

These control text, borders, and backgrounds:

VariablePurpose
--t-{mode}-foregroundPrimary text
--t-{mode}-foreground-mutedSecondary text
--t-{mode}-foreground-subtleTertiary text
--t-{mode}-borderStandard borders
--t-{mode}-border-mutedSubtle borders
--t-{mode}-backgroundPage background
--t-{mode}-surfaceCard/panel backgrounds

Replace {mode} with light or dark.

Other tokens​

Spacing​

VariableDefaultDescription
--t-spacing-unit4pxBase unit for all spacing (multipliers 0-32)

Changing this scales all spacing proportionally. With 5px, p={4} becomes 20px instead of 16px.

Typography​

VariableDescription
--t-font-family-headingHeadings (default: system sans-serif)
--t-font-family-bodyBody text (default: system sans-serif)
--t-font-family-monoCode (default: system monospace)
--t-font-size-xs through --t-font-size-5xlFont sizes (12px to 48px)
--t-font-weight-normal through --t-font-weight-boldFont weights (400 to 700)
--t-line-height-tight through --t-line-height-relaxedLine heights (1.25 to 1.75)

Borders & shadows​

VariableDescription
--t-radius-none through --t-radius-fullBorder radii (0px to 9999px)
--t-border-width-thin through --t-border-width-thickBorder widths (1px to 4px)
--t-shadow-sm through --t-shadow-lgBox shadows

Transitions​

VariableDefaultDescription
--t-transition-fast150msQuick transitions
--t-transition-normal250msStandard transitions
--t-transition-slow350msSlow transitions
--t-transition-easingease-in-outEasing function

Override scopes​

CSS variables cascade, so you can override at any level:

/* Global: affects entire app */
:root {
--t-light-primary-default: #dc2626;
}

/* Scoped: affects only this subtree */
.marketing-section {
--t-color-primary-default: #059669;
}

Scoped overrides use semantic variables (--t-color-*) because they apply to the active theme only.

Dark mode​

Control the color scheme with the data-theme attribute:

<!-- Follow system preference (default) -->
<html>

<!-- Or explicitly: -->
<html data-theme="auto">

<!-- Force light mode -->
<html data-theme="light">

<!-- Force dark mode -->
<html data-theme="dark">

Without an explicit value, Tosui follows the system color scheme. Set data-theme to force a mode.

Fonts​

Tosui uses system fonts by default. To use custom fonts:

Use Tosui's IBM Plex fonts​

import "@tosui/react/styles.css";
import "@tosui/react/fonts.css"; // Adds IBM Plex Sans and Mono

Use your own fonts​

/* custom-fonts.css */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');

:root {
--t-font-family-heading: 'Inter', sans-serif;
--t-font-family-body: 'Inter', sans-serif;
}
import "@tosui/react/styles.css";
import "./custom-fonts.css";

Token reference​

For the complete list of tokens and their default values, see the source: packages/react/src/styles/styles.css