Skip to content

Pixel Theme System

The Pixel library provides a comprehensive, portable Tailwind CSS theme system that integrates seamlessly with Angular Material while offering complete customization capabilities.

In your application’s main styles file:

// Import Pixel themes (includes CSS variables)
@use '@surkyl/pixel/styles/themes';
// Optional: Import component utilities
@use '@surkyl/pixel/styles/utilities';

In your tailwind.config.js:

const pixelPreset = require('@surkyl/pixel/tailwind-preset');
module.exports = {
presets: [pixelPreset],
content: [
// Your content paths
],
theme: {
extend: {
// Your custom extensions
}
}
};
import { ThemeService } from '@surkyl/pixel/core';
@Component({
selector: 'app-root',
template: `
<button (click)="themeService.toggleTheme()">
Toggle Theme
</button>
`
})
export class AppComponent {
constructor(public themeService: ThemeService) {}
}

The theme service automatically detects and responds to system theme changes in real-time:

  • Initial Load: Respects system preference if no user preference is saved
  • Live Updates: When users change their OS theme, the app updates automatically
  • User Override: Manual theme selection overrides system preference
  • Reset Option: Users can return to following system preference
// Check if currently using system preference
const isUsingSystemPref = themeService.useDevicePreference();
// Reset to follow system preference
themeService.useSystemPreference();

The library includes two default themes based on the Pixel logo colors:

  • pixel-light: Light theme with blue, green, and orange accents
  • pixel-dark: Dark theme with adjusted colors for optimal contrast

All theme values are exposed as CSS custom properties:

/* Color scales */
.my-element {
color: var(--pixel-color-primary-500);
background: var(--pixel-color-surface);
border-color: var(--pixel-color-border);
}
/* Semantic colors */
.success {
background: var(--pixel-color-success-bg);
color: var(--pixel-color-success-text);
border: 1px solid var(--pixel-color-success-border);
}
/* Spacing */
.spaced {
padding: var(--pixel-spacing-4);
margin: var(--pixel-spacing-2);
}
/* Shadows */
.card {
box-shadow: var(--pixel-shadow-md);
}
@use '@surkyl/pixel/styles/themes' as pixel;
// Create a custom theme
@include pixel.create-theme-variant(
'my-company-theme',
#1976d2, // Primary color
#388e3c, // Secondary color
false // Is dark theme?
);
import { ThemeService, createPixelTheme } from '@surkyl/pixel/core';
// Create a custom theme
const myTheme = createPixelTheme({
baseColors: {
primary: '#1976d2',
secondary: '#388e3c',
accent: '#ff6f00'
},
isDark: false,
overrides: {
colors: {
background: '#fafafa',
text: {
DEFAULT: '#212121'
}
}
}
});
// Register the theme
themeService.registerTheme('my-company-theme', myTheme);
// Apply the theme
themeService.setTheme('my-company-theme');
[data-theme="my-custom-theme"] {
/* Base colors */
--pixel-color-primary-500: #1976d2;
--pixel-color-secondary-500: #388e3c;
/* Override any other variables */
--pixel-color-background: #fafafa;
--pixel-color-text: #212121;
/* Component-specific */
--pixel-button-primary-bg: #1565c0;
--pixel-button-primary-hover: #0d47a1;
}
<!-- Primary color scale -->
<div class="bg-primary-500 text-white">Primary background</div>
<!-- Semantic colors -->
<div class="bg-surface border-border">Surface with border</div>
<!-- State colors -->
<div class="bg-success-bg text-success-text border-success-border">
Success message
</div>
<!-- Buttons -->
<button class="pixel-btn pixel-btn-primary pixel-btn-md">
Primary Button
</button>
<!-- Inputs -->
<input class="pixel-input pixel-input-error" placeholder="Error state">
<!-- Cards -->
<div class="pixel-card pixel-card-padded pixel-card-hover">
Card content
</div>
<!-- Badges -->
<span class="pixel-badge pixel-badge-success">Active</span>

The preset includes custom utilities:

<!-- Text gradient animation -->
<h1 class="pixel-text-gradient">Animated Gradient Text</h1>
<!-- Responsive utilities -->
<div class="pixel-hide-mobile">Hidden on mobile</div>
<div class="pixel-hide-desktop">Hidden on desktop</div>

Pixel provides seamless integration with Angular Material components through a dedicated theme adapter.

// In your styles.scss
@use '@surkyl/pixel/styles/themes' as pixel;
@use '@surkyl/pixel/styles/material-theme' as pixel-material;
html {
// Apply Material theme with Pixel colors
@include pixel-material.theme();
}
html {
@include pixel-material.theme((
color-scheme: 'light dark', // Auto-switch based on system
typography: 'Inter, sans-serif',
density: -1, // Compact density
));
}
// Base theme
html {
@include pixel-material.light-theme();
}
// Apply Material theme to Pixel variants
@include pixel-material.for-theme('pixel-dark', (
color-scheme: 'dark'
));

For detailed Material integration instructions, see the Material Theme Guide.

import { PixelThemeConfig } from '@surkyl/pixel/core';
const completeTheme: PixelThemeConfig = {
name: 'my-theme',
isDark: false,
colors: {
primary: { /* 50-950 scale */ },
secondary: { /* 50-950 scale */ },
accent: { /* 50-950 scale */ },
// ... all color definitions
},
typography: {
fontFamily: {
sans: 'Inter, system-ui, sans-serif',
mono: 'Fira Code, monospace'
}
},
spacing: { /* custom spacing scale */ },
borderRadius: { /* custom radius scale */ },
shadows: { /* custom shadows */ }
};
// Get available themes
const themes = themeService.getAvailableThemes();
// Returns: ['pixel-light', 'pixel-dark', 'my-custom-theme']
// Set specific theme
themeService.setTheme('my-custom-theme');
// Check if dark mode
if (themeService.isDarkMode()) {
// Dark mode specific logic
}
// Listen to theme changes
themeService.theme().subscribe(theme => {
console.log('Theme changed to:', theme);
});
import { applyPixelTheme } from '@surkyl/pixel/core';
// Apply custom CSS variables at runtime
applyPixelTheme(document.documentElement, {
'--pixel-color-primary-500': '#e91e63',
'--pixel-color-secondary-500': '#009688'
});
  1. Use Semantic Colors: Prefer semantic color variables over direct color scales

    /* Good */
    color: var(--pixel-color-text);
    /* Avoid */
    color: var(--pixel-blue-900);
  2. Leverage Tailwind Classes: Use Tailwind utilities for consistency

    <!-- Good -->
    <div class="bg-surface text-text border-border">
    <!-- Avoid -->
    <div style="background: var(--pixel-color-surface)">
  3. Theme-Aware Components: Make components adapt to theme changes

    .my-component {
    background: var(--pixel-color-surface);
    [data-theme="pixel-dark"] & {
    border: 1px solid var(--pixel-color-border);
    }
    }
  4. Test Multiple Themes: Always test your components with different themes

    it('should render correctly in dark mode', () => {
    themeService.setTheme('pixel-dark');
    // Test component appearance
    });
<!-- Before -->
<div class="bg-blue-500 text-white p-4">
<!-- After -->
<div class="bg-primary-500 text-white p-px-4">
// Before
.button {
background: #1976d2;
color: white;
}
// After
.button {
background: var(--pixel-button-primary-bg);
color: var(--pixel-button-primary-text);
}
// Before
@import '@angular/material/prebuilt-themes/indigo-pink.css';
// After
@use '@surkyl/pixel/styles/themes';
// Material components automatically use Pixel theme
  1. Ensure theme styles are imported in your main styles file
  2. Check that data-theme attribute is set on <html> element
  3. Verify CSS variables are available in DevTools
  1. Ensure Tailwind config includes the Pixel preset
  2. Check that PostCSS is processing your styles
  3. Verify content paths include all template files
  1. Register theme before using: themeService.registerTheme(name, config)
  2. Check browser console for any errors
  3. Verify theme configuration matches the interface
  1. Use CSS Variables: They update instantly without recompilation
  2. Lazy Load Themes: Load custom themes only when needed
  3. Optimize Tailwind: Use PurgeCSS in production
  4. Cache Theme Preference: ThemeService automatically handles localStorage

Check the libs/pixel/src/lib/core/components directory for examples of theme-aware components using this system.