Theming
Customize the visual theme for applications using @distri/react by overriding CSS variables. The theming system is built on Tailwind CSS with shadcn/ui design tokens.
Quick Start
Import the default theme files:
// Import both files for default theme
import '@distri/react/theme.css'; // Default color variables
import '@distri/react/globals.css'; // Tailwind utilities (required)
The theme.css provides default light/dark mode colors. The globals.css provides Tailwind utilities and component styles.
Custom Theme
Option 1: Override Specific Variables (Recommended)
/* your-app.css */
@import '@distri/react/globals.css';
/* Override specific variables */
:root {
--primary: 220 90% 50%; /* Custom blue primary */
}
.dark {
--primary: 220 80% 60%; /* Lighter blue for dark mode */
}
Option 2: Complete Theme Override
/* your-app.css */
@import '@distri/react/globals.css';
:root {
/* Core Colors */
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
/* Brand Colors */
--primary: 188 100% 28%;
--primary-foreground: 0 0% 100%;
--highlight: 188 70% 45%;
/* Secondary & Muted */
--secondary: 210 40% 96%;
--secondary-foreground: 222.2 84% 4.9%;
--muted: 210 40% 96%;
--muted-foreground: 215.4 16.3% 46.9%;
/* Accent & Destructive */
--accent: 188 55% 92%;
--accent-foreground: 188 80% 20%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
/* Borders & Input */
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 188 100% 28%;
/* Sidebar */
--sidebar: 0 0% 98%;
--sidebar-foreground: 240 5.3% 26.1%;
--sidebar-primary: 188 100% 28%;
--sidebar-accent: 240 4.8% 95.9%;
--sidebar-border: 220 13% 91%;
/* Layout */
--radius: 0.5rem;
--thread-content-max-width: 768px;
}
.dark {
--background: 220 16% 8%;
--foreground: 210 33% 95%;
--card: 220 17% 12%;
--card-foreground: 210 33% 95%;
--popover: 220 17% 12%;
--popover-foreground: 210 33% 95%;
--primary: 188 100% 28%;
--primary-foreground: 0 0% 100%;
--highlight: 188 70% 45%;
--secondary: 220 18% 16%;
--secondary-foreground: 210 33% 95%;
--muted: 220 18% 16%;
--muted-foreground: 215 20% 65%;
--accent: 188 30% 22%;
--accent-foreground: 188 70% 85%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 40% 98%;
--border: 220 18% 20%;
--input: 220 18% 20%;
--ring: 188 70% 45%;
--sidebar: 216 18% 6%;
--sidebar-foreground: 210 33% 95%;
--sidebar-primary: 188 70% 45%;
--sidebar-accent: 220 18% 14%;
--sidebar-border: 220 18% 18%;
}
CSS Variables Reference
Core Colors
| Variable | Light Default | Dark Default | Description |
|---|---|---|---|
--background | 0 0% 100% | 220 16% 8% | Page background |
--foreground | 222.2 84% 4.9% | 210 33% 95% | Main text color |
--card | 0 0% 100% | 220 17% 12% | Card backgrounds |
--card-foreground | Same as foreground | Same as foreground | Card text |
--popover | Same as card | Same as card | Popover/dropdown bg |
--popover-foreground | Same as foreground | Same as foreground | Popover text |
Brand Colors
| Variable | Light Default | Dark Default | Description |
|---|---|---|---|
--primary | 188 100% 28% | 188 100% 28% | Primary brand color (#007C91) |
--primary-foreground | 0 0% 100% | 0 0% 100% | Text on primary |
--highlight | 188 70% 45% | 188 70% 45% | Accent highlight (rgb(34,174,195)) |
Secondary & Muted
| Variable | Light Default | Dark Default | Description |
|---|---|---|---|
--secondary | 210 40% 96% | 220 18% 16% | Secondary backgrounds |
--secondary-foreground | 222.2 84% 4.9% | 210 33% 95% | Secondary text |
--muted | 210 40% 96% | 220 18% 16% | Muted/disabled backgrounds |
--muted-foreground | 215.4 16.3% 46.9% | 215 20% 65% | Muted text |
Accent & Destructive
| Variable | Light Default | Dark Default | Description |
|---|---|---|---|
--accent | 188 55% 92% | 188 30% 22% | Accent color |
--accent-foreground | 188 80% 20% | 188 70% 85% | Accent text |
--destructive | 0 84.2% 60.2% | 0 62.8% 30.6% | Error/delete actions |
--destructive-foreground | 210 40% 98% | 210 40% 98% | Destructive text |
Borders & Input
| Variable | Light Default | Dark Default | Description |
|---|---|---|---|
--border | 214.3 31.8% 91.4% | 220 18% 20% | Border color (#2a2f3a dark) |
--input | Same as border | Same as border | Input field borders |
--ring | 188 100% 28% | 188 70% 45% | Focus ring color |
Sidebar
| Variable | Light Default | Dark Default | Description |
|---|---|---|---|
--sidebar | 0 0% 98% | 216 18% 6% | Sidebar bg (#0c0e11 dark) |
--sidebar-foreground | 240 5.3% 26.1% | 210 33% 95% | Sidebar text |
--sidebar-primary | 188 100% 28% | 188 70% 45% | Active nav item |
--sidebar-accent | 240 4.8% 95.9% | 220 18% 14% | Hover states |
--sidebar-border | 220 13% 91% | 220 18% 18% | Sidebar borders |
Layout
| Variable | Default | Description |
|---|---|---|
--radius | 0.5rem | Border radius |
--thread-content-max-width | 768px | Max width for chat content |
Color Format
All colors use HSL format without the hsl() wrapper:
--primary: 188 100% 28%; /* H S% L% */
This allows using opacity modifiers:
background: hsl(var(--primary) / 0.5); /* 50% opacity */
Dark Mode
Dark mode is activated by adding the dark class to <html> or a parent element:
<html class="dark">
Or toggle via JavaScript:
document.documentElement.classList.toggle('dark');
React Integration
import { useState, useEffect } from 'react';
import '@distri/react/theme.css';
import '@distri/react/globals.css';
function App() {
const [darkMode, setDarkMode] = useState(false);
useEffect(() => {
if (darkMode) {
document.documentElement.classList.add('dark');
} else {
document.documentElement.classList.remove('dark');
}
}, [darkMode]);
return (
<div>
<button onClick={() => setDarkMode(!darkMode)}>
Toggle Dark Mode
</button>
{/* Your app content */}
</div>
);
}
Files
globals.css- Tailwind utilities + component styles (required)theme.css- Default color variables (imported by globals.css)
Best Practices
- Import globals.css first: Always import
globals.cssbefore your custom overrides - Use HSL format: Keep colors in HSL format for consistency and opacity support
- Define both light and dark: Always provide both
:rootand.darkvariants - Test contrast: Ensure sufficient contrast ratios for accessibility
- Use semantic names: Stick to the provided variable names for consistency