Customization
Customize UI Lab's design system to match your brand and requirements using Tailwind CSS design tokens.
Design tokens
UI Lab uses Tailwind CSS design tokens (CSS variables) to control all visual aspects. Modify tokens in your globals.css file to customize the entire design system:
/* globals.css */
@theme {
--color-base-50: #ffffff;
--color-base-100: #f8f8f8;
--color-base-200: #efefef;
/* ... continues to 950 */
--spacing: 0.25rem;
--radius-sm: 0.375rem;
--radius-md: 0.5rem;
--radius-lg: 0.75rem;
--radius-full: 9999px;
--font-sans: ui-sans-serif, system-ui, sans-serif;
--font-mono: 'Fira Code', monospace;
}All components automatically use these tokens. Change a single token and it updates across your entire application.
Color system
UI Lab's base palette automatically inverts across light and dark modes. The palette runs from 50 (lightest) to 950 (darkest).
Understanding the base palette
In dark mode (default), lower values (50-400) are light colors used for text and overlays. Higher values (600-950) are dark colors for backgrounds.
In light mode, this inverts: lower values become dark, higher values become light. This semantic approach eliminates the need to manage separate color systems.
/* Dark mode (default) */
--color-base-50: #ffffff; /* lightest, for text */
--color-base-100: #f8f8f8;
--color-base-200: #efefef;
--color-base-900: #1a1a1a; /* darkest, for bg */
--color-base-950: #0f0f0f;
/* Light mode inverts these automatically */Custom brand colors
Add accent colors for your brand. Keep the base palette but extend it with semantic colors:
@theme {
/* Keep base palette as-is */
--color-base-50: #ffffff;
/* ... */
/* Add accent colors */
--color-accent-500: #0066ff;
--color-accent-600: #0052cc;
--color-accent-700: #003d99;
/* Semantic colors */
--color-success-500: #10b981;
--color-warning-500: #f59e0b;
--color-destructive-500: #ef4444;
}Use these colors in components via Tailwind classes:
<Button className="bg-accent-500 hover:bg-accent-600">
Branded Action
</Button>Typography
Customize fonts, sizes, and weights through Tailwind configuration:
Font families
@theme {
--font-sans: 'Inter', ui-sans-serif, system-ui, sans-serif;
--font-mono: 'Fira Code', 'Courier New', monospace;
}Font sizes
UI Lab uses a modular scale for sizes. Adjust in Tailwind config:
export default {
theme: {
extend: {
fontSize: {
xs: ['0.75rem', { lineHeight: '1rem' }],
sm: ['0.875rem', { lineHeight: '1.25rem' }],
base: ['1rem', { lineHeight: '1.5rem' }],
lg: ['1.125rem', { lineHeight: '1.75rem' }],
xl: ['1.25rem', { lineHeight: '1.75rem' }],
'2xl': ['1.5rem', { lineHeight: '2rem' }],
'3xl': ['1.875rem', { lineHeight: '2.25rem' }],
'4xl': ['2.25rem', { lineHeight: '2.5rem' }],
},
},
},
};Font weights
Components use specific weights. Define available weights:
@theme {
--font-weight-regular: 400;
--font-weight-medium: 500;
--font-weight-semibold: 600;
--font-weight-bold: 700;
}Spacing and sizing
UI Lab uses a consistent spacing scale. The base unit is 0.25rem (4px):
@theme {
--spacing: 0.25rem; /* 4px base unit */
/* Components use multiples */
/* spacing-1 = 0.25rem, spacing-2 = 0.5rem, etc */
}
/* Use in components */
<div className="p-4 gap-6 m-8">
{/* p-4 = 1rem, gap-6 = 1.5rem, m-8 = 2rem */}
</div>Border radius follows the same consistent scale:
@theme {
--radius-sm: 0.375rem; /* 6px */
--radius-md: 0.5rem; /* 8px */
--radius-lg: 0.75rem; /* 12px */
--radius-full: 9999px;
}Creating component variants
UI Lab components support the variant prop. Create custom variants by extending component source:
Example: Custom button variant
If you copied component source into src/components/ui/button.tsx, you can add variants:
// components/ui/button.tsx
const variants = cva('base-button-styles', {
variants: {
variant: {
primary: 'bg-accent-500 text-background-950',
secondary: 'bg-background-800 text-foreground-50',
tertiary: 'bg-transparent text-accent-500',
destructive: 'bg-destructive-500 text-white',
outline: 'border border-accent-500 text-accent-500',
// Add your custom variant
gradient: 'bg-gradient-to-r from-accent-500 to-accent-600',
},
},
});
export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof variants> {}
export const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ variant = 'primary', ...props }, ref) => (
<button ref={ref} className={variants({ variant })} {...props} />
),
);Use your custom variant:
<Button variant="gradient">Gradient Button</Button>Extending Tailwind configuration
Add project-specific utilities and styles through Tailwind's extend mechanism:
// tailwind.config.js
export default {
theme: {
extend: {
colors: {
brand: '#0066ff',
'brand-light': '#e6f0ff',
},
spacing: {
gutter: '1.5rem',
'gutter-lg': '3rem',
},
keyframes: {
slideDown: {
'0%': { transform: 'translateY(-10px)', opacity: '0' },
'100%': { transform: 'translateY(0)', opacity: '1' },
},
},
animation: {
slideDown: 'slideDown 0.3s ease-out',
},
},
},
};Use these custom utilities in your components:
<div className="p-gutter bg-brand-light rounded animate-slideDown">
Custom styled element
</div>Theme switching
UI Lab's base palette automatically inverts in light mode. Implement theme switching at your app root:
// app/layout.tsx
'use client';
import { useState, useEffect } from 'react';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
const [theme, setTheme] = useState('dark');
useEffect(() => {
const saved = localStorage.getItem('theme') || 'dark';
setTheme(saved);
document.documentElement.setAttribute('data-theme', saved);
}, []);
const toggleTheme = () => {
const newTheme = theme === 'dark' ? 'light' : 'dark';
setTheme(newTheme);
localStorage.setItem('theme', newTheme);
document.documentElement.setAttribute('data-theme', newTheme);
};
return (
<html data-theme={theme}>
<body>
<button onClick={toggleTheme}>
Switch to {theme === 'dark' ? 'light' : 'dark'} mode
</button>
{children}
</body>
</html>
);
}In your CSS, use the data-theme attribute to adjust tokens:
/* globals.css */
html[data-theme="dark"] {
@theme {
--color-base-50: #ffffff;
--color-base-950: #0f0f0f;
}
}
html[data-theme="light"] {
@theme {
--color-base-50: #0f0f0f;
--color-base-950: #ffffff;
}
}Customization best practices
Use design tokens, not hard-coded values
Define tokens once in globals.css or tailwind.config.js, then reference them everywhere. This makes global changes trivial.
Keep spacing and sizing consistent
Use multiples of the base spacing unit (0.25rem) to maintain visual rhythm. Don't use arbitrary values like p-[13px].
Extend, don't override
Use theme.extend in Tailwind config to add custom utilities. Overriding the base theme can break component consistency.
Avoid component className overrides for layout
Don't use className to override a component's core styles. Instead, wrap components or create variants. This preserves component semantics and accessibility.