Skip to content

Customizing Themes

Make PACE.js match your brand with custom themes.


Default Theme

PACE.js ships with a purple gradient theme inspired by MillPond:

css
:root {
  --pace-primary: #667eea;
  --pace-accent: #764ba2;
  --pace-bg: #ffffff;
  --pace-text: #1a1a1a;
  --pace-font: Inter, system-ui, sans-serif;
}

CSS Custom Properties

All styling uses CSS custom properties (variables) for easy theming.

Complete Variable List

css
:root {
  /* Colors */
  --pace-primary: #667eea;
  --pace-accent: #764ba2;
  --pace-bg: #ffffff;
  --pace-bg-soft: #f9f9f9;
  --pace-bg-mute: #f1f1f1;
  --pace-text: #1a1a1a;
  --pace-text-secondary: #666666;
  --pace-text-muted: #999999;
  --pace-border: #e0e0e0;

  /* Typography */
  --pace-font: Inter, system-ui, sans-serif;
  --pace-font-mono: 'Fira Code', monospace;
  --pace-font-size-base: 16px;
  --pace-line-height: 1.6;

  /* Spacing */
  --pace-spacing-xs: 0.25rem;
  --pace-spacing-sm: 0.5rem;
  --pace-spacing-md: 1rem;
  --pace-spacing-lg: 1.5rem;
  --pace-spacing-xl: 2rem;

  /* Border Radius */
  --pace-radius-sm: 4px;
  --pace-radius-md: 8px;
  --pace-radius-lg: 12px;

  /* Shadows */
  --pace-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);
  --pace-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.1);
  --pace-shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.15);

  /* Transitions */
  --pace-transition-fast: 150ms ease;
  --pace-transition-base: 250ms ease;
  --pace-transition-slow: 350ms ease;

  /* Z-index */
  --pace-z-sidebar: 100;
  --pace-z-modal: 1000;
  --pace-z-tooltip: 2000;
}

Option 1: CSS Override

Override variables in your own stylesheet:

css
/* custom-theme.css */
:root {
  --pace-primary: #3b82f6;  /* Blue */
  --pace-accent: #8b5cf6;   /* Purple */
  --pace-font: 'Roboto', sans-serif;
}
html
<link rel="stylesheet" href="pace.min.css">
<link rel="stylesheet" href="custom-theme.css">

Option 2: JavaScript Configuration

Pass theme config to PACE constructor:

javascript
const pace = new PACE({
  container: '#app',
  products: './products.json',

  theme: {
    primary: '#3b82f6',
    accent: '#8b5cf6',
    font: 'Roboto, sans-serif',
    background: '#f8fafc',
    text: '#0f172a'
  }
})

Pre-built Themes

Blue Ocean

css
:root {
  --pace-primary: #0ea5e9;
  --pace-accent: #06b6d4;
  --pace-bg: #f0f9ff;
  --pace-text: #0c4a6e;
}

Green Forest

css
:root {
  --pace-primary: #10b981;
  --pace-accent: #059669;
  --pace-bg: #f0fdf4;
  --pace-text: #064e3b;
}

Orange Sunset

css
:root {
  --pace-primary: #f97316;
  --pace-accent: #ea580c;
  --pace-bg: #fff7ed;
  --pace-text: #7c2d12;
}

Monochrome

css
:root {
  --pace-primary: #18181b;
  --pace-accent: #3f3f46;
  --pace-bg: #ffffff;
  --pace-text: #09090b;
}

Dark Mode

Automatic Dark Mode

css
.dark {
  --pace-primary: #a78bfa;
  --pace-accent: #c4b5fd;
  --pace-bg: #1a1a2e;
  --pace-bg-soft: #252538;
  --pace-text: #ffffff;
  --pace-text-secondary: #d1d5db;
  --pace-border: #374151;
}

Toggle Implementation

javascript
// Dark mode toggle
const toggleDarkMode = () => {
  document.documentElement.classList.toggle('dark')
  localStorage.setItem('theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light')
}

// Persist preference
const savedTheme = localStorage.getItem('theme')
if (savedTheme === 'dark') {
  document.documentElement.classList.add('dark')
}

// System preference
if (window.matchMedia('(prefers-color-scheme: dark)').matches && !savedTheme) {
  document.documentElement.classList.add('dark')
}

Component-Specific Styling

Product Cards

css
.pace-product-card {
  border-left: 4px solid var(--pace-primary);
  background: linear-gradient(135deg, #ffffff 0%, #f9fafb 100%);
}

.pace-product-card:hover {
  transform: translateY(-4px);
  box-shadow: var(--pace-shadow-lg);
}

.pace-product-card h3 {
  color: var(--pace-primary);
  font-weight: 600;
}

Chat Messages

css
.pace-chat-message.user {
  background: var(--pace-primary);
  color: white;
  border-radius: 1rem 1rem 0 1rem;
}

.pace-chat-message.assistant {
  background: var(--pace-bg-soft);
  color: var(--pace-text);
  border-radius: 1rem 1rem 1rem 0;
  border-left: 3px solid var(--pace-accent);
}
css
.pace-nav-item {
  transition: all var(--pace-transition-base);
}

.pace-nav-item:hover {
  background: var(--pace-bg-soft);
  border-left: 4px solid var(--pace-primary);
}

.pace-nav-item.active {
  background: linear-gradient(135deg, var(--pace-primary), var(--pace-accent));
  color: white;
}

Brand Integration

Match Your Existing Site

css
/* Extract colors from your brand */
:root {
  --pace-primary: var(--brand-primary, #667eea);
  --pace-accent: var(--brand-accent, #764ba2);
  --pace-font: var(--brand-font, Inter);
}

/* Use your existing design tokens */
.pace-container {
  font-family: var(--pace-font);
  color: var(--pace-text);
}

Advanced Customization

Gradient Backgrounds

css
.pace-sidebar {
  background: linear-gradient(
    180deg,
    var(--pace-primary) 0%,
    var(--pace-accent) 100%
  );
}

.pace-product-card {
  background: linear-gradient(
    135deg,
    rgba(102, 126, 234, 0.05) 0%,
    rgba(118, 75, 162, 0.05) 100%
  );
}

Animations

css
@keyframes slideIn {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.pace-product-card {
  animation: slideIn var(--pace-transition-base);
}

.pace-chat-message {
  animation: slideIn 0.2s ease-out;
}

Custom Fonts

css
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&display=swap');

:root {
  --pace-font: 'Poppins', sans-serif;
}

h1, h2, h3 {
  font-weight: 700;
  letter-spacing: -0.02em;
}

Responsive Design

PACE.js is mobile-friendly by default, but you can customize breakpoints:

css
/* Mobile */
@media (max-width: 768px) {
  .pace-sidebar {
    width: 100%;
    height: auto;
    position: static;
  }

  .pace-product-grid {
    grid-template-columns: 1fr;
  }
}

/* Tablet */
@media (min-width: 769px) and (max-width: 1024px) {
  .pace-product-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* Desktop */
@media (min-width: 1025px) {
  .pace-product-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

Best Practices

1. Use Variables, Not Hard-Coded Colors

✅ Good:

css
.custom-element {
  color: var(--pace-primary);
}

❌ Bad:

css
.custom-element {
  color: #667eea;
}

2. Test Dark Mode

Always test your custom theme in both light and dark modes.

3. Maintain Contrast

Ensure text meets WCAG AA standards (4.5:1 ratio):

css
/* Good contrast */
:root {
  --pace-bg: #ffffff;
  --pace-text: #1a1a1a;  /* 16:1 ratio */
}

/* Poor contrast */
:root {
  --pace-bg: #f5f5f5;
  --pace-text: #999999;  /* 2.8:1 ratio - too low! */
}

4. Use System Fonts for Performance

css
:root {
  --pace-font: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}

Complete Theme Example

css
/* custom-theme.css */

/* Brand colors */
:root {
  --pace-primary: #3b82f6;
  --pace-accent: #8b5cf6;
  --pace-bg: #f8fafc;
  --pace-text: #0f172a;
  --pace-font: 'Inter', system-ui, sans-serif;
}

/* Dark mode */
.dark {
  --pace-primary: #60a5fa;
  --pace-accent: #a78bfa;
  --pace-bg: #0f172a;
  --pace-text: #f1f5f9;
}

/* Product cards */
.pace-product-card {
  border-radius: 12px;
  border: 1px solid #e2e8f0;
  transition: all 0.2s;
}

.pace-product-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 12px 24px rgba(59, 130, 246, 0.15);
  border-color: var(--pace-primary);
}

/* Chat messages */
.pace-chat-message.user {
  background: linear-gradient(135deg, #3b82f6, #8b5cf6);
  color: white;
  border-radius: 1rem 1rem 0.25rem 1rem;
}

.pace-chat-message.assistant {
  background: white;
  border: 1px solid #e2e8f0;
  border-radius: 1rem 1rem 1rem 0.25rem;
}

/* Navigation */
.pace-nav-item.active {
  background: linear-gradient(90deg, var(--pace-primary), var(--pace-accent));
  box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
}

/* Animations */
@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

.pace-product-card,
.pace-chat-message {
  animation: fadeIn 0.3s ease-out;
}

Make PACE.js yours with custom themes! 🎨