26 KiB
SSuite Customization and Theming Guide
🎨 Complete Guide to Styling and Overriding SSuite Libraries
This guide shows you how to customize and theme your Angular project using the SSuite library ecosystem. Learn how to override colors, typography, components, and create your own design system on top of the foundation.
📋 Prerequisites
Before customizing, ensure you have:
- SSuite libraries integrated (follow
CONSUMER_INTEGRATION_GUIDE.md) - ui-design-system added as a submodule (foundation library)
- Basic SCSS knowledge for advanced customizations
🏗️ Customization Architecture
SSuite uses a layered architecture for maximum flexibility:
Your Custom Theme
↓
Semantic Tokens ← Override here for colors, typography, spacing
↓
Base Tokens ← Override here for foundational values
↓
Components ← Override here for specific component styling
🎯 Approach 1: CSS Custom Properties (Recommended)
The easiest way to customize SSuite libraries using CSS variables.
1. Create Your Theme File
Create src/styles/theme.scss:
// ==========================================================================
// YOUR CUSTOM THEME
// ==========================================================================
// Import design system first
@use 'ui-design-system/src/styles' as ui;
// ==========================================================================
// 🎨 COLOR OVERRIDES
// ==========================================================================
:root {
// Primary Brand Colors
--color-primary: #6366f1; // Your brand primary (indigo)
--color-secondary: #8b5cf6; // Your brand secondary (purple)
--color-tertiary: #10b981; // Your accent color (emerald)
--color-error: #ef4444; // Error/danger color (red)
// Primary color variations
--color-primary-50: #eef2ff;
--color-primary-100: #e0e7ff;
--color-primary-500: #6366f1; // Main primary
--color-primary-600: #4f46e5;
--color-primary-700: #4338ca;
--color-primary-900: #312e81;
// Surface colors (backgrounds)
--color-surface: #ffffff;
--color-surface-variant: #f8fafc;
--color-surface-container: #f1f5f9;
--color-surface-dim: #e2e8f0;
// Text colors on your custom colors
--color-on-primary: #ffffff;
--color-on-secondary: #ffffff;
--color-on-surface: #1e293b;
// ==========================================================================
// ✍️ TYPOGRAPHY OVERRIDES
// ==========================================================================
// Font families (use your own fonts)
--font-family-sans: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
--font-family-mono: 'JetBrains Mono', 'Fira Code', monospace;
--font-family-display: 'Playfair Display', Georgia, serif;
// Font sizes
--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
// ==========================================================================
// 📏 SPACING & SIZING OVERRIDES
// ==========================================================================
// Border radius (adjust roundness)
--border-radius-sm: 0.25rem; // 4px - subtle
--border-radius-base: 0.5rem; // 8px - default
--border-radius-lg: 0.75rem; // 12px - rounded
--border-radius-xl: 1rem; // 16px - very rounded
// Component-specific spacing
--spacing-button-padding-x: 1.5rem; // Button horizontal padding
--spacing-button-padding-y: 0.75rem; // Button vertical padding
--spacing-card-padding: 1.5rem; // Card interior padding
--spacing-section: 4rem; // Section spacing
}
2. Import Your Theme
In src/styles.scss:
// Import your custom theme (this sets CSS variables)
@import 'styles/theme';
// Global styles using your theme
body {
font-family: var(--font-family-sans);
background-color: var(--color-surface);
color: var(--color-on-surface);
}
// Apply theme to headings
h1, h2, h3, h4, h5, h6 {
font-family: var(--font-family-display);
color: var(--color-primary);
}
// Custom link styling
a {
color: var(--color-primary);
&:hover {
color: var(--color-primary-600);
}
}
🎯 Approach 2: SCSS Variable Overrides (Advanced)
For deeper customization, override SCSS variables before importing SSuite.
1. Create Advanced Theme File
Create src/styles/advanced-theme.scss:
// ==========================================================================
// ADVANCED SCSS VARIABLE OVERRIDES
// ==========================================================================
// ==========================================================================
// 🎨 COLOR VARIABLE OVERRIDES (before importing ui-design-system)
// ==========================================================================
// Override semantic colors
$semantic-color-brand-primary: #7c3aed !default; // Purple brand
$semantic-color-brand-secondary: #059669 !default; // Emerald secondary
$semantic-color-brand-accent: #dc2626 !default; // Red accent
// Override feedback colors
$semantic-color-success: #10b981 !default; // Custom green
$semantic-color-warning: #f59e0b !default; // Custom amber
$semantic-color-danger: #ef4444 !default; // Custom red
$semantic-color-info: #3b82f6 !default; // Custom blue
// Override surface colors
$semantic-color-surface-primary: #ffffff !default; // Pure white
$semantic-color-surface-secondary: #f9fafb !default; // Off-white
$semantic-color-surface-elevated: #f3f4f6 !default; // Light gray
// ==========================================================================
// ✍️ TYPOGRAPHY VARIABLE OVERRIDES
// ==========================================================================
// Font families
$base-typography-font-family-sans: 'Inter', sans-serif !default;
$base-typography-font-family-mono: 'JetBrains Mono', monospace !default;
$base-typography-font-family-display: 'Playfair Display', serif !default;
// Font sizes
$base-typography-font-size-xs: 0.75rem !default; // 12px
$base-typography-font-size-sm: 0.875rem !default; // 14px
$base-typography-font-size-base: 1rem !default; // 16px
$base-typography-font-size-lg: 1.125rem !default; // 18px
$base-typography-font-size-xl: 1.25rem !default; // 20px
$base-typography-font-size-2xl: 1.5rem !default; // 24px
$base-typography-font-size-3xl: 1.875rem !default; // 30px
$base-typography-font-size-4xl: 2.25rem !default; // 36px
// Line heights
$base-typography-line-height-tight: 1.25 !default;
$base-typography-line-height-snug: 1.375 !default;
$base-typography-line-height-normal: 1.5 !default;
$base-typography-line-height-relaxed: 1.625 !default;
// ==========================================================================
// 📏 SPACING & LAYOUT OVERRIDES
// ==========================================================================
// Border radius
$semantic-border-button-radius: 0.75rem !default; // Rounded buttons
$semantic-border-card-radius: 1rem !default; // Very rounded cards
$semantic-border-input-radius: 0.5rem !default; // Moderate inputs
// Spacing values
$semantic-spacing-section-padding: 5rem !default; // Generous sections
$semantic-spacing-card-padding: 2rem !default; // Spacious cards
$semantic-spacing-interactive-button-padding-x: 2rem !default; // Wide buttons
$semantic-spacing-interactive-button-padding-y: 0.875rem !default; // Tall buttons
// NOW import ui-design-system (it will use your overridden variables)
@use 'ui-design-system/src/styles' as ui;
2. Use Advanced Theme
In src/styles.scss:
// Import your advanced theme
@import 'styles/advanced-theme';
// Global styles
body {
font-family: ui.$base-typography-font-family-sans;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
}
// Custom component styles
.custom-hero {
background: linear-gradient(
45deg,
var(--color-primary),
var(--color-secondary)
);
color: white;
padding: var(--spacing-section);
border-radius: var(--border-radius-lg);
}
🎯 Approach 3: Component-Specific Overrides
Target specific SSuite components for surgical customizations.
1. Override Button Components
Create src/styles/component-overrides.scss:
// ==========================================================================
// COMPONENT-SPECIFIC OVERRIDES
// ==========================================================================
@use 'ui-design-system/src/styles' as ui;
// ==========================================================================
// 🔘 BUTTON OVERRIDES
// ==========================================================================
// Override all buttons
ui-button, .ui-button {
// Custom button base
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
box-shadow: 0 4px 14px 0 rgba(0, 0, 0, 0.1);
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
// Custom hover effects
&:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px 0 rgba(0, 0, 0, 0.15);
}
&:active {
transform: translateY(0);
}
}
// Primary button overrides
ui-button[variant="primary"], .ui-button--primary {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
&:hover {
background: linear-gradient(135deg, #5a6fd8 0%, #6a4190 100%);
}
}
// Secondary button overrides
ui-button[variant="secondary"], .ui-button--secondary {
background: transparent;
border: 2px solid var(--color-primary);
color: var(--color-primary);
&:hover {
background: var(--color-primary);
color: var(--color-on-primary);
}
}
// Outline button overrides
ui-button[variant="outline"], .ui-button--outline {
border: 2px solid currentColor;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
}
// ==========================================================================
// 📋 FORM OVERRIDES
// ==========================================================================
// Input field overrides
ui-text-input, .ui-text-input {
input {
background: rgba(255, 255, 255, 0.9);
border: 2px solid transparent;
border-radius: var(--border-radius-lg);
padding: 1rem 1.25rem;
font-size: var(--font-size-base);
transition: all 0.2s ease;
&:focus {
background: rgba(255, 255, 255, 1);
border-color: var(--color-primary);
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
outline: none;
}
}
}
// Form field overrides
ui-form-field, .ui-form-field {
.field-label {
font-weight: 600;
color: var(--color-primary);
margin-bottom: 0.75rem;
}
.field-error {
color: var(--color-danger);
font-size: var(--font-size-sm);
margin-top: 0.5rem;
}
}
// ==========================================================================
// 🃏 CARD OVERRIDES
// ==========================================================================
ui-card, .ui-card {
background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: var(--border-radius-xl);
box-shadow:
0 8px 32px rgba(31, 38, 135, 0.37),
0 4px 16px rgba(31, 38, 135, 0.2);
transition: all 0.3s ease;
&:hover {
transform: translateY(-4px);
box-shadow:
0 16px 64px rgba(31, 38, 135, 0.4),
0 8px 32px rgba(31, 38, 135, 0.25);
}
}
// ==========================================================================
// 🚀 LANDING PAGE OVERRIDES
// ==========================================================================
// Hero section overrides
ui-hero-section, .ui-hero-section {
background: linear-gradient(
135deg,
rgba(102, 126, 234, 0.9) 0%,
rgba(118, 75, 162, 0.9) 100%
);
backdrop-filter: blur(10px);
.hero-title {
font-family: var(--font-family-display);
background: linear-gradient(45deg, #fff, #e2e8f0);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
}
// Feature grid overrides
ui-feature-grid, .ui-feature-grid {
.feature-item {
background: rgba(255, 255, 255, 0.1);
border-radius: var(--border-radius-lg);
padding: 2rem;
transition: all 0.3s ease;
&:hover {
background: rgba(255, 255, 255, 0.2);
transform: scale(1.05);
}
}
}
2. Use Component Overrides
In src/styles.scss:
// Import design system
@use 'ui-design-system/src/styles' as ui;
// Import your component overrides
@import 'styles/component-overrides';
🎯 Approach 4: Dark Mode Implementation
Create a comprehensive dark mode theme.
1. Create Dark Mode Theme
Create src/styles/dark-theme.scss:
// ==========================================================================
// DARK MODE THEME
// ==========================================================================
@use 'ui-design-system/src/styles' as ui;
// Dark mode CSS variables
[data-theme="dark"] {
// ==========================================================================
// 🌙 DARK MODE COLORS
// ==========================================================================
// Primary colors (slightly brighter for dark mode)
--color-primary: #818cf8; // Lighter indigo
--color-secondary: #a78bfa; // Lighter purple
--color-tertiary: #34d399; // Lighter emerald
// Dark surfaces
--color-surface: #0f172a; // Very dark blue
--color-surface-variant: #1e293b; // Dark blue-gray
--color-surface-container: #334155; // Medium blue-gray
--color-surface-elevated: #475569; // Light blue-gray
--color-surface-dim: #64748b; // Muted blue-gray
// Dark mode text colors
--color-on-surface: #f8fafc; // Light text on dark
--color-on-primary: #1e1b4b; // Dark text on light primary
--color-on-secondary: #2d1b69; // Dark text on light secondary
// Border colors for dark mode
--color-border: #374151;
--color-border-light: #4b5563;
// ==========================================================================
// 🌙 DARK MODE COMPONENT OVERRIDES
// ==========================================================================
// Card styling in dark mode
ui-card, .ui-card {
background: rgba(30, 41, 59, 0.8);
border-color: rgba(71, 85, 105, 0.3);
&:hover {
background: rgba(51, 65, 85, 0.8);
border-color: rgba(71, 85, 105, 0.5);
}
}
// Input styling in dark mode
ui-text-input input, .ui-text-input input {
background: rgba(30, 41, 59, 0.8);
border-color: var(--color-border);
color: var(--color-on-surface);
&::placeholder {
color: #94a3b8;
}
&:focus {
background: rgba(30, 41, 59, 1);
border-color: var(--color-primary);
}
}
// Button adjustments for dark mode
ui-button[variant="secondary"], .ui-button--secondary {
border-color: var(--color-primary);
color: var(--color-primary);
&:hover {
background: var(--color-primary);
color: var(--color-on-primary);
}
}
}
2. Dark Mode Toggle Component
Create a theme switcher:
// src/app/components/theme-toggle.component.ts
import { Component } from '@angular/core';
import { ThemeSwitcherComponent } from 'ui-essentials';
@Component({
selector: 'app-theme-toggle',
standalone: true,
imports: [ThemeSwitcherComponent],
template: `
<ui-theme-switcher
[themes]="themes"
(themeChange)="onThemeChange($event)">
</ui-theme-switcher>
`,
styles: [`
:host {
position: fixed;
top: 1rem;
right: 1rem;
z-index: 1000;
}
`]
})
export class ThemeToggleComponent {
themes = [
{ id: 'light', name: 'Light', icon: '☀️' },
{ id: 'dark', name: 'Dark', icon: '🌙' }
];
onThemeChange(theme: string) {
document.documentElement.setAttribute('data-theme', theme);
localStorage.setItem('theme', theme);
}
}
3. Initialize Theme
In src/app/app.component.ts:
import { Component, OnInit } from '@angular/core';
import { ThemeToggleComponent } from './components/theme-toggle.component';
@Component({
selector: 'app-root',
standalone: true,
imports: [ThemeToggleComponent],
template: `
<div class="app">
<app-theme-toggle></app-theme-toggle>
<!-- Your app content -->
</div>
`
})
export class AppComponent implements OnInit {
ngOnInit() {
// Initialize theme from localStorage
const savedTheme = localStorage.getItem('theme') || 'light';
document.documentElement.setAttribute('data-theme', savedTheme);
}
}
🎯 Approach 5: Custom Brand Components
Create your own branded components on top of SSuite.
1. Custom Branded Button
Create src/app/components/brand-button.component.ts:
import { Component, Input } from '@angular/core';
import { ButtonComponent } from 'ui-essentials';
@Component({
selector: 'app-brand-button',
standalone: true,
imports: [ButtonComponent],
template: `
<ui-button
[variant]="variant"
[size]="size"
[disabled]="disabled"
class="brand-button"
[class.gradient]="gradient"
[class.glass]="glass">
<ng-content></ng-content>
</ui-button>
`,
styles: [`
.brand-button {
font-weight: 700;
text-transform: uppercase;
letter-spacing: 1px;
position: relative;
overflow: hidden;
// Gradient effect
&.gradient {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
&:before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
transition: left 0.5s;
}
&:hover:before {
left: 100%;
}
}
// Glass morphism effect
&.glass {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
color: white;
&:hover {
background: rgba(255, 255, 255, 0.2);
}
}
}
`]
})
export class BrandButtonComponent {
@Input() variant: 'primary' | 'secondary' | 'outline' = 'primary';
@Input() size: 'sm' | 'md' | 'lg' = 'md';
@Input() disabled = false;
@Input() gradient = false;
@Input() glass = false;
}
2. Custom Hero Section
Create src/app/components/brand-hero.component.ts:
import { Component, Input } from '@angular/core';
import { HeroSectionComponent } from 'ui-landing-pages';
import { BrandButtonComponent } from './brand-button.component';
@Component({
selector: 'app-brand-hero',
standalone: true,
imports: [HeroSectionComponent, BrandButtonComponent],
template: `
<div class="brand-hero">
<div class="hero-background"></div>
<div class="hero-content">
<h1 class="hero-title">{{ title }}</h1>
<p class="hero-subtitle">{{ subtitle }}</p>
<div class="hero-actions">
<app-brand-button
[gradient]="true"
size="lg">
{{ ctaText }}
</app-brand-button>
<app-brand-button
[glass]="true"
variant="outline"
size="lg">
{{ secondaryCta }}
</app-brand-button>
</div>
</div>
</div>
`,
styles: [`
.brand-hero {
position: relative;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.hero-background {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
&:before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><circle cx="50" cy="50" r="1" fill="rgba(255,255,255,0.1)"/></svg>') repeat;
animation: float 20s infinite linear;
}
}
@keyframes float {
0% { transform: translateY(0) rotate(0deg); }
100% { transform: translateY(-100px) rotate(360deg); }
}
.hero-content {
text-align: center;
z-index: 2;
max-width: 800px;
padding: 2rem;
}
.hero-title {
font-size: clamp(2.5rem, 8vw, 5rem);
font-weight: 900;
margin-bottom: 1.5rem;
background: linear-gradient(45deg, #fff, #e2e8f0);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
line-height: 1.1;
}
.hero-subtitle {
font-size: clamp(1.125rem, 3vw, 1.5rem);
color: rgba(255, 255, 255, 0.9);
margin-bottom: 3rem;
line-height: 1.6;
}
.hero-actions {
display: flex;
gap: 1.5rem;
justify-content: center;
flex-wrap: wrap;
}
`]
})
export class BrandHeroComponent {
@Input() title = 'Welcome to Our Platform';
@Input() subtitle = 'Create amazing experiences with our design system';
@Input() ctaText = 'Get Started';
@Input() secondaryCta = 'Learn More';
}
🎯 Real-World Examples
Example 1: E-commerce Theme
// src/styles/ecommerce-theme.scss
:root {
// E-commerce focused colors
--color-primary: #059669; // Forest green (trust)
--color-secondary: #dc2626; // Red (urgency/sales)
--color-success: #10b981; // Success green
--color-warning: #f59e0b; // Warning amber
// Product-focused typography
--font-family-sans: 'Open Sans', sans-serif;
--font-family-display: 'Poppins', sans-serif;
// E-commerce spacing
--spacing-product-card: 1.25rem;
--spacing-checkout: 2rem;
// Trust-building shadows
--shadow-product-card: 0 4px 12px rgba(0,0,0,0.1);
--shadow-button-primary: 0 4px 14px rgba(5,150,105,0.3);
}
// Product card styling
.product-card {
border-radius: var(--border-radius-lg);
box-shadow: var(--shadow-product-card);
transition: all 0.3s ease;
&:hover {
transform: translateY(-4px);
box-shadow: 0 12px 24px rgba(0,0,0,0.15);
}
}
Example 2: SaaS Platform Theme
// src/styles/saas-theme.scss
:root {
// SaaS professional colors
--color-primary: #3b82f6; // Professional blue
--color-secondary: #6366f1; // Indigo accent
--color-success: #10b981; // Success green
// Dashboard-focused spacing
--spacing-sidebar: 16rem;
--spacing-dashboard-padding: 2rem;
--spacing-card-gap: 1.5rem;
// Modern typography
--font-family-sans: 'Inter', sans-serif;
--font-size-dashboard-title: 2rem;
--font-size-widget-title: 1.25rem;
}
// Dashboard layout
.dashboard-layout {
display: grid;
grid-template-columns: var(--spacing-sidebar) 1fr;
min-height: 100vh;
.sidebar {
background: var(--color-surface-variant);
border-right: 1px solid var(--color-border);
}
.main-content {
padding: var(--spacing-dashboard-padding);
}
}
📚 Advanced Customization Tips
1. Use CSS Custom Properties for Runtime Changes
// Dynamically change theme colors
export class ThemeService {
setThemeColor(property: string, value: string) {
document.documentElement.style.setProperty(`--${property}`, value);
}
// Example: User customization
applyUserTheme(userTheme: UserTheme) {
this.setThemeColor('color-primary', userTheme.primaryColor);
this.setThemeColor('font-family-sans', userTheme.fontFamily);
this.setThemeColor('border-radius-base', userTheme.borderRadius);
}
}
2. Component-Level CSS Custom Properties
ui-button {
// Component-specific custom properties
--btn-padding-x: 2rem;
--btn-font-weight: 700;
--btn-border-radius: 0.75rem;
}
// Modify specific button instances
.hero-button {
--btn-padding-x: 3rem;
--btn-font-size: 1.25rem;
}
3. Responsive Theme Adjustments
:root {
--font-size-hero: 2.5rem;
--spacing-section: 3rem;
}
@media (min-width: 768px) {
:root {
--font-size-hero: 4rem;
--spacing-section: 5rem;
}
}
✅ Best Practices
1. Layer Your Customizations
- Start with CSS custom properties for quick changes
- Use SCSS variables for deeper customizations
- Create component overrides for specific needs
2. Maintain Consistency
- Define a clear color palette
- Use consistent spacing scales
- Maintain typography hierarchy
3. Test Across Components
- Ensure your theme works across all SSuite components
- Test in both light and dark modes
- Verify accessibility (contrast ratios)
4. Performance Considerations
- Use CSS custom properties for dynamic changes
- Avoid excessive nesting in component overrides
- Minimize redundant style declarations
5. Documentation
- Document your theme variables
- Create a style guide for your team
- Maintain examples of themed components
🚀 Quick Start Templates
Minimal Customization (5 minutes)
// src/styles.scss
@use 'ui-design-system/src/styles' as ui;
:root {
--color-primary: #your-brand-color;
--font-family-sans: 'Your Font', sans-serif;
}
Medium Customization (30 minutes)
- Use Approach 1 (CSS Custom Properties)
- Add dark mode support
- Create 2-3 component overrides
Full Customization (2+ hours)
- Use Approach 2 (SCSS Variable Overrides)
- Implement comprehensive dark mode
- Create branded components
- Add responsive theme adjustments
🎉 You're Ready to Theme!
With this guide, you can create beautiful, branded experiences using the SSuite library ecosystem. Start small with CSS custom properties and gradually add more advanced customizations as needed.
Your themed application will maintain the robust functionality of SSuite components while expressing your unique brand identity! 🎨✨