Getting Started

Theming

Understand the theming system and how to customize design tokens.

The exaBase Design System uses CSS custom properties (CSS variables) as design tokens, mapped to Tailwind CSS utility classes via Tailwind v4's @theme inline directive. Light and dark themes are defined in :root and .dark selectors in your globals.css.

For dark mode setup, see Dark Mode.

How It Works

The theming system has two layers:

Layer 1: CSS Custom Properties

Semantic color tokens are defined as CSS variables in :root (light) and .dark (dark):

globals.css
:root {
  --primary: rgb(37, 99, 244);
  --primary-foreground: rgb(255, 255, 255);
}

.dark {
  --primary: rgb(37, 99, 244);
  --primary-foreground: rgb(255, 255, 255);
}

Layer 2: Tailwind @theme inline

The @theme inline block maps these CSS variables to Tailwind's --color-* namespace, making them available as utility classes:

globals.css
@theme inline {
  --color-primary: var(--primary);
  --color-primary-foreground: var(--primary-foreground);
  /* ... */
}

This allows you to use bg-primary, text-primary-foreground, and other utility classes in your components:

<Button className="bg-primary text-primary-foreground">Click me</Button>

Naming Conventions

background and foreground

Colors follow a background / foreground pair convention. The background variable is used for the background color of the component and the foreground variable is used for the text color on that background.

--background: rgb(255, 255, 255); /* body background */
--foreground: rgb(8, 10, 12);     /* body text */

The background suffix is omitted when naming a component's background color:

--primary: rgb(37, 99, 244);            /* background suffix omitted */
--primary-foreground: rgb(255, 255, 255); /* text on primary background */

hovered and pressed

Interactive colors have hovered and pressed variants for mouse-over and mouse-down states:

--primary-hovered: rgb(58, 114, 245);  /* + White 10% */
--primary-pressed: rgb(81, 130, 246);  /* + White 20% */

text

The text suffix is used for text displayed on the default --background, while foreground is for text on its counterpart component background:

--background: rgb(255, 255, 255);
--info: rgb(0, 177, 242);
--info-foreground: rgb(255, 255, 255); /* text on --info background */
--info-text: rgb(0, 152, 208);        /* text on --background */

muted

The muted suffix is a softened tone variant, used for subtle backgrounds in components like Alert:

--destructive-muted: rgb(254, 227, 226);
--info-muted: rgb(224, 246, 253);

Opacity Modifier Syntax

Most colors support Tailwind's opacity modifier syntax:

<div className="bg-primary/50">...</div>

However, colors with a pre-applied alpha channel do not support this syntax:

--secondary: rgba(103, 120, 145, 0.1);
--secondary-hovered: rgba(103, 120, 145, 0.2);
--secondary-pressed: rgba(103, 120, 145, 0.3);
--accent: var(--secondary);
--accent-pressed: var(--secondary-hovered);
// Not supported
<div className="bg-secondary/50">...</div>

Color Tokens

Base

TokenLightDarkDescription
background
Default background (<body> etc.)
foreground
Default text color

Surface

TokenLightDarkDescription
card
Background for <Card>
card-foreground
Text on card
popover
Background for popovers and dropdowns
popover-foreground
Text on popover

Variant

TokenLightDarkDescription
primary
Primary color
primary-hovered
Primary hover state
primary-pressed
Primary pressed state
primary-foreground
Text on primary
primary-text
Primary text on background
secondary
Secondary color
secondary-hovered
Secondary hover state
secondary-pressed
Secondary pressed state
secondary-foreground
Text on secondary
destructive
Destructive / error color
destructive-hovered
Destructive hover state
destructive-pressed
Destructive pressed state
destructive-foreground
Text on destructive
destructive-text
Destructive text on background
destructive-muted
Destructive muted background
info
Info color
info-foreground
Text on info
info-text
Info text on background
info-muted
Info muted background
success
Success color
success-foreground
Text on success
success-text
Success text on background
success-muted
Success muted background
warning
Warning color
warning-foreground
Text on warning
warning-text
Warning text on background
warning-muted
Warning muted background

Utility

TokenLightDarkDescription
muted
Muted background
muted-foreground
Muted text
accent
Accent for hover effects (ghost buttons)
accent-pressed
Accent pressed state
accent-foreground
Text on accent
border
Default border color
input
Border color for inputs
ring
Focus ring color
TokenLightDarkDescription
sidebar
Sidebar background
sidebar-foreground
Sidebar text
sidebar-primary
Sidebar primary
sidebar-primary-foreground
Sidebar primary text
sidebar-accent
Sidebar accent
sidebar-accent-foreground
Sidebar accent text
sidebar-border
Sidebar border
sidebar-ring
Sidebar focus ring

Typography

The default font stack is configured via CSS variables and mapped to font-sans:

globals.css
@theme inline {
  --font-sans: var(--font-inter), var(--font-noto-sans-jp), sans-serif;
}

The font variables --font-inter and --font-noto-sans-jp are set by the fonts component. See Installation for setup instructions.

Border Radius

A base --radius variable controls all border radius sizes. Each size is derived from this base value:

globals.css
:root {
  --radius: 0.625rem;
}

@theme inline {
  --radius-xs: calc(var(--radius) - 6px);    /* 4px */
  --radius-sm: calc(var(--radius) - 4px);    /* 6px */
  --radius-md: calc(var(--radius) - 2px);    /* 8px */
  --radius-lg: var(--radius);                /* 10px */
  --radius-xl: calc(var(--radius) + 4px);    /* 14px */
  --radius-2xl: calc(var(--radius) + 8px);   /* 18px */
  --radius-3xl: calc(var(--radius) + 12px);  /* 22px */
  --radius-4xl: calc(var(--radius) + 16px);  /* 26px */
}

Customizing the Theme

Changing Colors

Override any color by modifying the CSS variable in globals.css. No JavaScript configuration is needed:

globals.css
:root {
  --primary: rgb(99, 102, 241);           /* your custom primary */
  --primary-hovered: rgb(129, 140, 248);
  --primary-pressed: rgb(165, 180, 252);
}

.dark {
  --primary: rgb(129, 140, 248);          /* your custom dark primary */
  --primary-hovered: rgb(165, 180, 252);
  --primary-pressed: rgb(199, 210, 254);
}

Adding Custom Colors

To add a new color token, define the CSS variable and register it in @theme inline:

globals.css
@theme inline {
  --color-brand: var(--brand);
  --color-brand-foreground: var(--brand-foreground);
}

:root {
  --brand: rgb(255, 107, 53);
  --brand-foreground: rgb(255, 255, 255);
}

.dark {
  --brand: rgb(255, 140, 100);
  --brand-foreground: rgb(255, 255, 255);
}

Now bg-brand, text-brand-foreground, and other utility classes are available.

On this page