Skip to main content

Customization

Tosui is fully customizable via CSS variables. Override any design token to match your brand, and the entire component library adapts automatically.

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";

That's it—Tosui's theme switching handles the rest automatically.

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 appropriate primitive based on 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

Rule of thumb: Use primitives for theming, semantic for overrides.

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;
}
{/* Inline: affects only this element and children */}
<Box style={{ '--t-color-primary-default': '#f59e0b' }}>
<Button>Uses amber primary</Button>
</Box>

Note: Scoped and inline overrides use semantic variables (--t-color-*) since they apply to the current 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">

Tosui automatically switches between light and dark values based on this attribute or system preference.

Fonts

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

Option 1: Use Tosui's IBM Plex Fonts

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

Option 2: 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