Design System
Customize colors, typography, and components - make ProductReady match your brand
Design System
ProductReady's design system is built with CSS variables for easy customization. Change colors, fonts, and spacing without touching component code.
For designers & PMs: This guide uses plain English and visual examples. No deep coding required!
Color System
How it Works
Colors are defined as CSS variables in src/app/global.css. Change them once, they apply everywhere.
Example:
:root {
--color-primary: 220 90% 56%; /* Blue */
--color-accent: 142 71% 45%; /* Green */
}Format: HSL (Hue, Saturation, Lightness) without the hsl() wrapper.
Why HSL? Easy to create color variations (just change lightness for hover states).
Change Your Brand Colors
Step 1: Pick your colors
Use a tool like Coolors.co or Realtime Colors
Step 2: Convert to HSL
Most tools show HSL values. If you have hex (#3B82F6):
- Use HSL converter
- Example:
#3B82F6→hsl(220, 90%, 56%)
Step 3: Update global.css
Open src/app/global.css and find:
:root {
/* Change these values! */
--color-primary: 220 90% 56%; /* Your main brand color */
--color-accent: 142 71% 45%; /* Accent/CTA color */
--color-background: 0 0% 100%; /* Page background */
--color-foreground: 222 47% 11%; /* Text color */
}Example - Purple brand:
:root {
--color-primary: 271 81% 56%; /* Purple */
--color-accent: 321 82% 56%; /* Pink */
}Save → Refresh → Your app is now purple! 🎨
Dark Mode Colors
ProductReady has separate colors for dark mode:
.dark {
--color-primary: 220 90% 66%; /* Lighter in dark mode */
--color-background: 224 71% 4%; /* Dark background */
--color-foreground: 213 31% 91%; /* Light text */
}Tip: Make colors slightly lighter in dark mode for better contrast.
Complete Color Palette
All available color variables:
| Variable | Purpose | Light Mode | Dark Mode |
|---|---|---|---|
--color-background | Page background | White | Dark |
--color-foreground | Text | Dark | Light |
--color-primary | Brand color (buttons, links) | Brand | Lighter brand |
--color-accent | Highlights, CTAs | Accent | Lighter accent |
--color-muted | Subtle backgrounds | Light gray | Dark gray |
--color-border | Borders, dividers | Medium gray | Dark gray |
--color-success | Success states | Green | Light green |
--color-warning | Warnings | Yellow | Light yellow |
--color-error | Errors | Red | Light red |
Typography
Change Fonts
Step 1: Choose fonts from Google Fonts
Example: "Inter" for body, "Playfair Display" for headings
Step 2: Update src/app/layout.tsx
import { Inter, Playfair_Display } from 'next/font/google';
const inter = Inter({ subsets: ['latin'] });
const playfair = Playfair_Display({ subsets: ['latin'] });
export default function RootLayout({ children }) {
return (
<html>
<body className={inter.className}>
{children}
</body>
</html>
);
}Step 3: Use heading font
<h1 className={playfair.className}>
Beautiful Heading
</h1>Font Sizes
Customize font sizes in global.css:
:root {
--font-size-xs: 0.75rem; /* 12px */
--font-size-sm: 0.875rem; /* 14px */
--font-size-base: 1rem; /* 16px */
--font-size-lg: 1.125rem; /* 18px */
--font-size-xl: 1.25rem; /* 20px */
--font-size-2xl: 1.5rem; /* 24px */
--font-size-3xl: 1.875rem; /* 30px */
--font-size-4xl: 2.25rem; /* 36px */
}Use in components:
<p className="text-base">Normal text</p>
<h1 className="text-4xl">Big heading</h1>Spacing
Consistent spacing makes UI feel professional.
Spacing scale (in global.css):
:root {
--spacing-0: 0;
--spacing-1: 0.25rem; /* 4px */
--spacing-2: 0.5rem; /* 8px */
--spacing-3: 0.75rem; /* 12px */
--spacing-4: 1rem; /* 16px */
--spacing-6: 1.5rem; /* 24px */
--spacing-8: 2rem; /* 32px */
--spacing-12: 3rem; /* 48px */
--spacing-16: 4rem; /* 64px */
}Use with Tailwind:
<div className="p-4">Padding 16px</div>
<div className="mt-8 mb-4">Margin top 32px, bottom 16px</div>Border Radius
Control roundness of cards, buttons, inputs.
:root {
--radius-sm: 0.25rem; /* 4px - subtle */
--radius-md: 0.5rem; /* 8px - default */
--radius-lg: 0.75rem; /* 12px - cards */
--radius-xl: 1rem; /* 16px - very round */
--radius-full: 9999px; /* Pills, avatars */
}Make everything more rounded:
:root {
--radius-md: 0.75rem; /* Change default */
--radius-lg: 1rem;
}Component Customization
Buttons
Buttons use CSS variables. Customize in src/components/ui/button.tsx:
<button className="btn-primary">
Click Me
</button>Styles in global.css:
.btn-primary {
background: hsl(var(--color-primary));
color: white;
padding: var(--spacing-3) var(--spacing-6);
border-radius: var(--radius-md);
font-weight: 600;
}
.btn-primary:hover {
background: hsl(var(--color-primary) / 0.9);
}Change button style globally: Just update the CSS!
Cards
Cards are background containers with borders.
<div className="card">
<h3>Card Title</h3>
<p>Card content</p>
</div>Style:
.card {
background: hsl(var(--color-background));
border: 1px solid hsl(var(--color-border));
border-radius: var(--radius-lg);
padding: var(--spacing-6);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}Forms & Inputs
Customize input fields:
input, textarea {
background: hsl(var(--color-background));
border: 1px solid hsl(var(--color-border));
border-radius: var(--radius-md);
padding: var(--spacing-3) var(--spacing-4);
font-size: var(--font-size-base);
}
input:focus {
outline: 2px solid hsl(var(--color-primary));
outline-offset: 2px;
}Dark Mode
Toggle Dark Mode
ProductReady uses next-themes for dark mode.
Add toggle button:
'use client';
import { useTheme } from 'next-themes';
export function ThemeToggle() {
const { theme, setTheme } = useTheme();
return (
<button onClick={() => setTheme(theme === 'dark' ? 'light' : 'dark')}>
{theme === 'dark' ? '☀️' : '🌙'}
</button>
);
}Customize Dark Mode Colors
Edit .dark section in global.css:
.dark {
/* Dark backgrounds */
--color-background: 224 71% 4%;
--color-card: 224 71% 6%;
/* Light text */
--color-foreground: 213 31% 91%;
/* Adjust primary for dark mode */
--color-primary: 220 90% 66%; /* Slightly lighter */
}Tip: Test contrast with WebAIM Contrast Checker
AI Prompt: Customize Design
Copy-paste this to ChatGPT/Claude/Cursor:
I'm using ProductReady (Next.js boilerplate). Help me customize the design:
Brand Colors:
- Primary: [Your color name/hex]
- Accent: [Your color name/hex]
Typography:
- Body font: [Font name]
- Heading font: [Font name]
Style:
- Rounded corners: [More/Less rounded]
- Spacing: [Tight/Normal/Spacious]
- Dark mode: [Yes/No]
Generate the CSS variables for global.css and show me how to update fonts in layout.tsxAI will give you copy-paste code!
Using KUI Components
ProductReady uses the KUI component library from the monorepo.
Important: Don't modify packages/kui directly! Create wrapper components instead.
How to Customize KUI Components
Example: Customize Button
- Import KUI component
- Create wrapper in your app
- Add custom styles
// src/components/ui/custom-button.tsx
import { Button } from 'kui/button';
import './custom-button.css';
export function CustomButton({ children, ...props }) {
return (
<Button className="custom-button" {...props}>
{children}
</Button>
);
}/* src/components/ui/custom-button.css */
.custom-button {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
padding: 12px 24px;
font-weight: 700;
}Now use <CustomButton> instead of <Button> in your app!
Responsive Design
ProductReady is mobile-first. Use Tailwind breakpoints:
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3">
{/* 1 column on mobile, 2 on tablet, 3 on desktop */}
</div>Breakpoints:
sm:- 640px+md:- 768px+lg:- 1024px+xl:- 1280px+2xl:- 1536px+
Example - Responsive padding:
<div className="p-4 md:p-8 lg:p-12">
{/* 16px mobile, 32px tablet, 48px desktop */}
</div>Accessibility
Color Contrast
Ensure text is readable:
Minimum contrast ratios:
- Normal text: 4.5:1
- Large text (18px+): 3:1
Test with WebAIM Contrast Checker
Focus States
Always show focus for keyboard navigation:
button:focus-visible {
outline: 2px solid hsl(var(--color-primary));
outline-offset: 2px;
}Semantic HTML
Use proper HTML elements:
✅ <button>Click Me</button>
❌ <div onClick={...}>Click Me</div>
✅ <nav>...</nav>
❌ <div className="nav">...</div>Design Tokens Cheat Sheet
Quick reference for all design tokens:
Colors
--color-background
--color-foreground
--color-primary
--color-accent
--color-muted
--color-border
--color-success
--color-warning
--color-errorSpacing
--spacing-1 through --spacing-16
/* Use with: p-4, mt-8, gap-6, etc. */Typography
--font-size-xs through --font-size-4xl
--font-weight-normal (400)
--font-weight-medium (500)
--font-weight-semibold (600)
--font-weight-bold (700)Border Radius
--radius-sm, --radius-md, --radius-lg, --radius-xl, --radius-fullBest Practices
✅ Do
- Use CSS variables for consistency
- Test both light and dark modes
- Check color contrast for accessibility
- Use semantic HTML elements
- Keep spacing consistent (stick to scale)
- Test on mobile devices
❌ Don't
- Hardcode colors in components
- Modify
packages/kuidirectly - Use too many different font sizes
- Ignore dark mode styles
- Skip focus states
- Use
<div>for everything
Quick Customization Recipes
Recipe 1: Minimalist B&W
:root {
--color-primary: 0 0% 9%; /* Black */
--color-accent: 0 0% 45%; /* Gray */
--color-background: 0 0% 100%; /* White */
--color-foreground: 0 0% 9%; /* Black */
}
.dark {
--color-primary: 0 0% 98%; /* White */
--color-background: 0 0% 9%; /* Black */
--color-foreground: 0 0% 98%; /* White */
}Recipe 2: Vibrant Startup
:root {
--color-primary: 271 81% 56%; /* Purple */
--color-accent: 346 77% 50%; /* Pink */
--radius-md: 1rem; /* Extra rounded */
--radius-lg: 1.5rem;
}Recipe 3: Professional SaaS
:root {
--color-primary: 220 90% 56%; /* Blue */
--color-accent: 142 71% 45%; /* Green */
--radius-md: 0.5rem; /* Subtle rounding */
--radius-lg: 0.75rem;
}Next Steps
🎨 Make it yours! The best designs are unique to your brand.