Theming
Customize the visual appearance of your vertical application.
CSS Variables
The template uses CSS custom properties for theming, allowing runtime theme switching.
Base Theme
/* src/app/globals.css */
:root {
/* Colors */
--background: 0 0% 100%;
--foreground: 222.2 47.4% 11.2%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
--accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
/* Borders */
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 222.2 47.4% 11.2%;
/* Layout */
--radius: 0.5rem;
}
Dark Theme
[data-theme="dark"] {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--primary: 210 40% 98%;
--primary-foreground: 222.2 47.4% 11.2%;
/* ... other dark mode values */
}
Tenant Branding
Each tenant can have custom colors and assets.
Per-Tenant CSS
Create tenant-specific styles:
/* src/app/tenants/my-tenant.css */
[data-tenant="my-tenant"] {
--primary: 250 100% 50%;
--primary-foreground: 0 0% 100%;
}
Import in your layout:
// src/app/layout.tsx
import './tenants/my-tenant.css';
Tenant Config Theming
Add theme to your tenant config:
export const myTenantConfig: EAIConfig = {
tenantId: 'my-tenant',
displayName: 'My Application',
theme: {
primaryColor: '#6366f1',
secondaryColor: '#f1f5f9',
logo: '/logos/my-tenant-logo.svg',
favicon: '/favicons/my-tenant.ico',
},
// ... rest of config
};
Logo and Assets
Logo Placement
{
component: 'Header',
props: {
logo: '/logos/my-logo.svg',
logoAlt: 'My Company',
logoWidth: 150,
},
}
Favicon
Set per-tenant favicons:
// src/app/layout.tsx
export const metadata = {
icons: {
icon: getTenantFavicon(tenantId),
},
};
Theme Switching
Store-Based Theme
Use the store to manage theme preference:
// Tenant config
store: {
ui: {
initialState: {
theme: 'light', // or 'dark', 'system'
},
persist: true,
},
}
Theme Toggle Component
'use client';
import { useStoreValue, useSetStore } from '@enterpriseaigroup/client';
export function ThemeToggle() {
const theme = useStoreValue('ui.theme');
const setStore = useSetStore();
const toggleTheme = () => {
const newTheme = theme === 'light' ? 'dark' : 'light';
setStore('ui.theme', newTheme, 'ThemeToggle');
document.documentElement.setAttribute('data-theme', newTheme);
};
return (
<button onClick={toggleTheme}>
{theme === 'light' ? '🌙' : '☀️'}
</button>
);
}
Tailwind Configuration
Extend Tailwind with your brand colors:
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
brand: {
50: '#f0f9ff',
100: '#e0f2fe',
// ... full palette
900: '#0c4a6e',
},
},
},
},
};
Use in components:
<button className="bg-brand-500 hover:bg-brand-600">
Click me
</button>
Component Variants
Use variants for consistent styling:
// src/components/ui/button.tsx
const buttonVariants = cva(
'inline-flex items-center justify-center rounded-md',
{
variants: {
variant: {
default: 'bg-primary text-primary-foreground',
destructive: 'bg-destructive text-destructive-foreground',
outline: 'border border-input bg-background',
secondary: 'bg-secondary text-secondary-foreground',
ghost: 'hover:bg-accent hover:text-accent-foreground',
link: 'text-primary underline-offset-4 hover:underline',
},
size: {
default: 'h-10 px-4 py-2',
sm: 'h-9 px-3',
lg: 'h-11 px-8',
icon: 'h-10 w-10',
},
},
}
);
Best Practices
- Use CSS variables for colors that need to change
- Use Tailwind classes for layout and spacing
- Keep themes simple - fewer variables are easier to maintain
- Test both themes - ensure readability in light and dark
- Respect system preference - support
prefers-color-scheme
Related Documentation
- Custom Components - Component styling
- ADR-005: Styling - Styling decisions