| name | Enterprise CSS Patterns Library |
| description | Comprehensive enterprise CSS architecture patterns for large-scale applications with design systems, governance, and team workflows |
| category | enterprise |
| version | 1.0.0 |
| keywords | ["enterprise","css-architecture","design-system","itcss","atomic-design","monorepo","governance","bem","versioning","migration","performance","storybook"] |
Enterprise CSS Patterns Library
A comprehensive collection of production-ready CSS patterns and architectures for enterprise-scale applications. This skill covers design systems, governance frameworks, component libraries, team workflows, and migration strategies.
Table of Contents
- Enterprise CSS Architecture Patterns
- Large-Scale Design Systems
- CSS Governance Framework
- Component Library Architecture
- Versioning & Migration
- Monorepo CSS Management
- Team Workflows & CI/CD
- Storybook Documentation
- Legacy Migration Strategies
- Performance & Optimization
Enterprise CSS Architecture Patterns
ITCSS (Inverted Triangle CSS)
Description: A scalable and maintainable CSS architecture based on specificity levels, from generic to explicit.
Architecture Layers:
@import 'settings/colors';
@import 'settings/typography';
@import 'settings/breakpoints';
@import 'settings/spacing';
@import 'tools/mixins';
@import 'tools/functions';
@import 'tools/placeholders';
@import 'generic/reset';
@import 'generic/normalize';
@import 'generic/box-sizing';
@import 'elements/headings';
@import 'elements/links';
@import 'elements/forms';
@import 'elements/tables';
@import 'objects/container';
@import 'objects/grid';
@import 'objects/media';
@import 'objects/list-bare';
@import 'components/buttons';
@import 'components/cards';
@import 'components/modals';
@import 'components/navigation';
@import 'utilities/spacing';
@import 'utilities/typography';
@import 'utilities/visibility';
@import 'utilities/colors';
TypeScript Configuration Interface:
interface ITCSSConfig {
basePath: string;
layers: {
settings: boolean;
tools: boolean;
generic: boolean;
elements: boolean;
objects: boolean;
components: boolean;
utilities: boolean;
};
output: {
sourcemaps: boolean;
minify: boolean;
outputPath: string;
};
budgets: {
maxSize: number;
maxSpecificity: number;
};
}
function initializeITCSS(config: ITCSSConfig): Promise<BuildResult> {
}
Design Tokens:
:root {
--color-blue-100: #e3f2fd;
--color-blue-500: #2196f3;
--color-blue-900: #0d47a1;
--color-primary: var(--color-blue-500);
--color-primary-hover: var(--color-blue-600);
--color-surface: #ffffff;
--color-text: #1f2937;
}
:root {
--spacing-unit: 8px;
--spacing-xs: calc(var(--spacing-unit) * 0.5);
--spacing-sm: calc(var(--spacing-unit) * 1);
--spacing-md: calc(var(--spacing-unit) * 2);
--spacing-lg: calc(var(--spacing-unit) * 3);
--spacing-xl: calc(var(--spacing-unit) * 4);
}
Accessibility Notes:
- Maintain logical cascade order for screen readers
- Use semantic HTML elements in Elements layer
- Ensure utility classes don't override accessibility features
- WCAG 2.1 AA: Minimum 4.5:1 contrast ratio for text
Performance Metrics:
- ITCSS reduces specificity wars, improving parse time by 15-20%
- Modular architecture enables tree-shaking unused CSS
- Critical CSS can be extracted from Settings + Generic + Elements layers
BEM at Enterprise Scale
Description: Block Element Modifier methodology adapted for large teams and complex applications.
Enterprise BEM Pattern:
$namespace: 'ds-';
.#{$namespace}card {
--card-background: var(--color-surface);
--card-padding: var(--spacing-md);
--card-border-radius: var(--radius-md);
--card-shadow: var(--shadow-sm);
--card-transition: var(--transition-default);
background: var(--card-background);
padding: var(--card-padding);
border-radius: var(--card-border-radius);
box-shadow: var(--card-shadow);
transition: var(--card-transition);
&__header {
display: flex;
align-items: center;
justify-content: space-between;
padding-block-end: var(--spacing-sm);
border-block-end: 1px solid var(--color-border);
}
&__title {
font-size: var(--font-size-lg);
font-weight: var(--font-weight-semibold);
color: var(--color-text-primary);
margin: 0;
}
&__actions {
display: flex;
gap: var(--spacing-xs);
}
&__body {
padding-block: var(--spacing-md);
}
&__footer {
display: flex;
justify-content: flex-end;
gap: var(--spacing-sm);
padding-block-start: var(--spacing-sm);
border-block-start: 1px solid var(--color-border);
}
&--elevated {
--card-shadow: var(--shadow-md);
&:hover {
--card-shadow: var(--shadow-lg);
}
}
&--interactive {
cursor: pointer;
&:hover {
--card-background: var(--color-surface-hover);
}
&:focus-visible {
outline: 2px solid var(--color-focus);
outline-offset: 2px;
}
&:active {
transform: translateY(1px);
}
}
&--outlined {
--card-shadow: none;
border: 1px solid var(--color-border);
}
&--compact {
--card-padding: var(--spacing-sm);
}
&--large {
--card-padding: var(--spacing-lg);
}
&--loading {
position: relative;
pointer-events: none;
&::after {
content: '';
position: absolute;
inset: 0;
background: rgba(255, 255, 255, 0.8);
display: flex;
align-items: center;
justify-content: center;
}
}
&--error {
border-inline-start: 4px solid var(--color-error);
}
}
TypeScript Interface:
interface BEMComponent {
block: string;
namespace?: string;
elements: {
name: string;
required: boolean;
description: string;
}[];
modifiers: {
name: string;
type: 'visual' | 'size' | 'state';
values?: string[];
description: string;
}[];
metadata: {
version: string;
status: 'stable' | 'beta' | 'deprecated';
accessibility: string[];
};
}
function bem(
block: string,
element?: string,
modifier?: string,
namespace: string = 'ds-'
): string {
let className = `${namespace}${block}`;
if (element) className += `__${element}`;
if (modifier) className += `--${modifier}`;
return className;
}
const cardClass = bem('card', 'header', 'elevated');
Accessibility Guidelines:
- Use semantic HTML:
<article class="ds-card"> instead of <div>
- Add ARIA roles when needed:
role="region" for cards with headings
- Ensure interactive cards have
tabindex="0" and keyboard handlers
- Provide focus indicators with minimum 2px width and 4.5:1 contrast
Atomic Design Pattern
Description: Hierarchical component system from atoms to pages for systematic UI construction.
Atomic Design Implementation:
.a-button {
--button-background: var(--color-primary);
--button-color: var(--color-primary-contrast);
--button-padding: var(--spacing-sm) var(--spacing-md);
--button-border-radius: var(--radius-md);
--button-font-size: var(--font-size-base);
--button-font-weight: var(--font-weight-medium);
--button-transition: all 0.2s ease;
display: inline-flex;
align-items: center;
justify-content: center;
gap: var(--spacing-xs);
padding: var(--button-padding);
background: var(--button-background);
color: var(--button-color);
border: none;
border-radius: var(--button-border-radius);
font-size: var(--button-font-size);
font-weight: var(--button-font-weight);
font-family: inherit;
line-height: 1;
text-decoration: none;
cursor: pointer;
user-select: none;
transition: var(--button-transition);
&:focus-visible {
outline: 2px solid var(--color-focus);
outline-offset: 2px;
}
&:hover:not(:disabled) {
filter: brightness(1.1);
}
&:active:not(:disabled) {
transform: translateY(1px);
}
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
}
.a-input {
--input-background: var(--color-surface);
--input-border: 1px solid var(--color-border);
--input-padding: var(--spacing-sm) var(--spacing-md);
--input-border-radius: var(--radius-md);
--input-font-size: var(--font-size-base);
width: 100%;
padding: var(--input-padding);
background: var(--input-background);
border: var(--input-border);
border-radius: var(--input-border-radius);
font-size: var(--input-font-size);
font-family: inherit;
transition: border-color 0.2s ease;
&:focus {
outline: none;
border-color: var(--color-primary);
}
&::placeholder {
color: var(--color-text-tertiary);
}
&:disabled {
background: var(--color-surface-disabled);
cursor: not-allowed;
}
}
.m-form-field {
display: flex;
flex-direction: column;
gap: var(--spacing-xs);
&__label {
@extend .a-label;
font-weight: var(--font-weight-medium);
color: var(--color-text-primary);
}
&__input {
@extend .a-input;
}
&__hint {
font-size: var(--font-size-sm);
color: var(--color-text-tertiary);
}
&__error {
font-size: var(--font-size-sm);
color: var(--color-error);
display: none;
}
&--error {
.m-form-field__input {
border-color: var(--color-error);
}
.m-form-field__error {
display: block;
}
}
}
.m-search-box {
position: relative;
display: flex;
align-items: center;
&__icon {
position: absolute;
left: var(--spacing-sm);
color: var(--color-text-tertiary);
pointer-events: none;
}
&__input {
@extend .a-input;
padding-inline-start: calc(var(--spacing-md) + 24px);
padding-inline-end: calc(var(--spacing-md) + 24px);
}
&__clear {
@extend .a-button;
position: absolute;
right: var(--spacing-xs);
padding: var(--spacing-xs);
background: transparent;
color: var(--color-text-tertiary);
&:hover {
color: var(--color-text-primary);
}
}
}
.o-header {
--header-height: 64px;
--header-background: var(--color-surface);
--header-border: 1px solid var(--color-border);
position: sticky;
top: 0;
z-index: 100;
height: var(--header-height);
background: var(--header-background);
border-block-end: var(--header-border);
&__container {
display: flex;
align-items: center;
justify-content: space-between;
height: 100%;
padding-inline: var(--spacing-lg);
max-width: var(--container-max-width);
margin-inline: auto;
}
&__brand {
display: flex;
align-items: center;
gap: var(--spacing-md);
}
&__nav {
flex: 1;
display: flex;
justify-content: center;
}
&__actions {
display: flex;
align-items: center;
gap: var(--spacing-sm);
}
}
.o-data-table {
--table-border: 1px solid var(--color-border);
--table-header-background: var(--color-surface-secondary);
width: 100%;
border: var(--table-border);
border-radius: var(--radius-lg);
overflow: hidden;
&__header {
background: var(--table-header-background);
font-weight: var(--font-weight-semibold);
}
&__body {
}
&__footer {
display: flex;
justify-content: space-between;
align-items: center;
padding: var(--spacing-md);
border-block-start: var(--table-border);
}
}
TypeScript Atomic Design Interface:
interface AtomicDesignRegistry {
atoms: {
button: ComponentDefinition;
input: ComponentDefinition;
label: ComponentDefinition;
icon: ComponentDefinition;
};
molecules: {
formField: ComponentDefinition;
searchBox: ComponentDefinition;
card: ComponentDefinition;
};
organisms: {
header: ComponentDefinition;
dataTable: ComponentDefinition;
sidebar: ComponentDefinition;
};
templates: {
dashboardLayout: TemplateDefinition;
authLayout: TemplateDefinition;
};
}
interface ComponentDefinition {
name: string;
category: 'atom' | 'molecule' | 'organism';
dependencies: string[];
props: Record<string, PropDefinition>;
variants: string[];
accessibility: AccessibilityRequirements;
}
interface PropDefinition {
type: 'string' | 'number' | 'boolean';
required: boolean;
default?: any;
description: string;
}
interface AccessibilityRequirements {
role?: string;
ariaLabels: string[];
keyboardNavigation: boolean;
wcagLevel: 'A' | 'AA' | 'AAA';
}
Composition Guidelines:
- Atoms compose only primitives (no other atoms)
- Molecules compose 2-5 atoms
- Organisms compose molecules and atoms (max 10 components)
- Templates define page structure using organisms
- Pages are instances of templates with real content
Large-Scale Design Systems
Design System Architecture
Description: Complete enterprise design system structure with tokens, components, and patterns.
@import 'tokens/colors';
@import 'tokens/typography';
@import 'tokens/spacing';
@import 'tokens/shadows';
@import 'tokens/animations';
@import 'tokens/breakpoints';
@import 'tokens/z-index';
@import 'foundation/reset';
@import 'foundation/mixins';
@import 'foundation/functions';
@import 'foundation/grid';
@import 'foundation/breakpoints';
@import 'components/core/*';
@import 'components/layout/*';
@import 'components/navigation/*';
@import 'components/data/*';
@import 'components/feedback/*';
@import 'patterns/forms/*';
@import 'patterns/cards/*';
@import 'patterns/modals/*';
@import 'patterns/workflows/*';
@import 'patterns/dashboards/*';
@import 'themes/default';
@import 'themes/dark';
@import 'themes/high-contrast';
@import 'themes/brand-a';
@import 'themes/brand-b';
Design Token Management
3-Tier Token System:
$primitive-colors: (
// Blue scale
'blue-100': #e3f2fd,
'blue-200': #bbdefb,
'blue-300': #90caf9,
'blue-400': #64b5f6,
'blue-500': #2196f3,
'blue-600': #1e88e5,
'blue-700': #1976d2,
'blue-800': #1565c0,
'blue-900': #0d47a1,
// Gray scale
'gray-100': #f5f5f5,
'gray-200': #eeeeee,
'gray-300': #e0e0e0,
'gray-400': #bdbdbd,
'gray-500': #9e9e9e,
'gray-600': #757575,
'gray-700': #616161,
'gray-800': #424242,
'gray-900': #212121,
// Semantic colors
'green-500': #4caf50,
'green-600': #43a047,
'amber-500': #ffc107,
'amber-600': #ffb300,
'red-500': #f44336,
'red-600': #e53935
);
$semantic-colors: (
// Primary brand color
'primary': map-get($primitive-colors, 'blue-600'),
'primary-hover': map-get($primitive-colors, 'blue-700'),
'primary-active': map-get($primitive-colors, 'blue-800'),
'primary-light': map-get($primitive-colors, 'blue-100'),
// Secondary brand color
'secondary': map-get($primitive-colors, 'gray-700'),
'secondary-hover': map-get($primitive-colors, 'gray-800'),
// Feedback colors
'success': map-get($primitive-colors, 'green-600'),
'success-light': map-get($primitive-colors, 'green-100'),
'warning': map-get($primitive-colors, 'amber-600'),
'warning-light': map-get($primitive-colors, 'amber-100'),
'error': map-get($primitive-colors, 'red-600'),
'error-light': map-get($primitive-colors, 'red-100'),
'info': map-get($primitive-colors, 'blue-500'),
'info-light': map-get($primitive-colors, 'blue-100'),
// Neutral colors
'text-primary': map-get($primitive-colors, 'gray-900'),
'text-secondary': map-get($primitive-colors, 'gray-700'),
'text-tertiary': map-get($primitive-colors, 'gray-500'),
'text-disabled': map-get($primitive-colors, 'gray-400'),
// Surface colors
'surface': #ffffff,
'surface-secondary': map-get($primitive-colors, 'gray-100'),
'surface-tertiary': map-get($primitive-colors, 'gray-200'),
// Border colors
'border': map-get($primitive-colors, 'gray-300'),
'border-strong': map-get($primitive-colors, 'gray-400')
);
$component-tokens: (
// Button tokens
'button-primary-bg': map-get($semantic-colors, 'primary'),
'button-primary-text': #ffffff,
'button-primary-hover-bg': map-get($semantic-colors, 'primary-hover'),
'button-secondary-bg': map-get($semantic-colors, 'secondary'),
'button-secondary-text': #ffffff,
'button-padding-sm': 8px 12px,
'button-padding-md': 12px 16px,
'button-padding-lg': 16px 24px,
// Card tokens
'card-background': map-get($semantic-colors, 'surface'),
'card-border': 1px solid map-get($semantic-colors, 'border'),
'card-shadow': 0 2px 4px rgba(0, 0, 0, 0.1),
'card-shadow-hover': 0 4px 8px rgba(0, 0, 0, 0.15),
'card-padding': 16px,
'card-border-radius': 8px,
// Input tokens
'input-bg': map-get($semantic-colors, 'surface'),
'input-border': 1px solid map-get($semantic-colors, 'border'),
'input-border-focus': 2px solid map-get($semantic-colors, 'primary'),
'input-text': map-get($semantic-colors, 'text-primary'),
'input-placeholder': map-get($semantic-colors, 'text-tertiary'),
'input-padding': 8px 12px,
'input-border-radius': 4px
);
@function validate-token($token-map, $key) {
@if not map-has-key($token-map, $key) {
@error "Token '#{$key}' not found in token map. Available tokens: #{map-keys($token-map)}";
}
@return map-get($token-map, $key);
}
@function token($key) {
@return validate-token($component-tokens, $key);
}
.button {
background: token('button-primary-bg');
color: token('button-primary-text');
padding: token('button-padding-md');
}
CSS Custom Properties Export:
:root {
@each $name, $value in $primitive-colors {
--color-#{$name}: #{$value};
}
@each $name, $value in $semantic-colors {
--semantic-#{$name}: #{$value};
}
@each $name, $value in $component-tokens {
--#{$name}: #{$value};
}
--font-family-primary: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
--font-family-mono: 'SF Mono', Monaco, 'Cascadia Code', monospace;
--font-size-xs: 0.75rem;
--font-size-sm: 0.875rem;
--font-size-base: 1rem;
--font-size-lg: 1.125rem;
--font-size-xl: 1.25rem;
--font-size-2xl: 1.5rem;
--font-size-3xl: 1.875rem;
--font-size-4xl: 2.25rem;
--font-weight-normal: 400;
--font-weight-medium: 500;
--font-weight-semibold: 600;
--font-weight-bold: 700;
--spacing-unit: 8px;
--spacing-xs: 4px;
--spacing-sm: 8px;
--spacing-md: 16px;
--spacing-lg: 24px;
--spacing-xl: 32px;
--spacing-2xl: 48px;
--spacing-3xl: 64px;
--radius-none: 0;
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 12px;
--radius-xl: 16px;
--radius-full: 9999px;
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
--shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.15);
--transition-fast: 150ms ease;
--transition-default: 250ms ease;
--transition-slow: 350ms ease;
--ease-in: cubic-bezier(0.4, 0, 1, 1);
--ease-out: cubic-bezier(0, 0, 0.2, 1);
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
--z-dropdown: 1000;
--z-sticky: 1020;
--z-fixed: 1030;
--z-modal-backdrop: 1040;
--z-modal: 1050;
--z-popover: 1060;
--z-tooltip: 1070;
}
TypeScript Token Interface:
enum TokenTier {
Primitive = 1,
Semantic = 2,
Component = 3
}
interface ColorToken {
name: string;
value: string;
tier: TokenTier;
contrastRatio?: number;
wcagLevel?: 'AA' | 'AAA';
}
interface SpacingToken {
name: string;
value: string;
multiplier: number;
}
interface TypographyToken {
fontSize: string;
lineHeight: string;
fontWeight: number;
letterSpacing?: string;
}
interface DesignTokenRegistry {
colors: {
primitive: Map<string, ColorToken>;
semantic: Map<string, ColorToken>;
component: Map<string, ColorToken>;
};
spacing: Map<string, SpacingToken>;
typography: Map<string, TypographyToken>;
shadows: Map<string, string>;
radii: Map<string, string>;
zIndex: Map<string, number>;
}
class TokenManager {
private registry: DesignTokenRegistry;
getColor(name: string, tier: TokenTier = TokenTier.Component): string {
let tokenMap: Map<string, ColorToken>;
switch (tier) {
case TokenTier.Primitive:
tokenMap = this.registry.colors.primitive;
break;
case TokenTier.Semantic:
tokenMap = this.registry.colors.semantic;
break;
case TokenTier.Component:
tokenMap = this.registry.colors.component;
break;
}
const token = tokenMap.get(name);
if (!token) {
throw new Error(`Color token '${name}' not found in tier ${tier}`);
}
return token.value;
}
validateContrast(foreground: string, background: string): 'AA' | 'AAA' | null {
const ratio = this.calculateContrastRatio(foreground, background);
if (ratio >= 7) return 'AAA';
if (ratio >= 4.5) return 'AA';
return null;
}
private calculateContrastRatio(color1: string, color2: string): number {
return 4.5;
}
}
CSS Governance Framework
Governance Charter
Structure:
# CSS Governance Charter
Version: 2.0.0
Effective Date: 2024-01-01
Review Cycle: Quarterly
## 1. Governance Structure
### Design System Council
**Role:** Strategic oversight and major decision approval
**Members:**
- Chief Design Officer (Chair)
- Lead Frontend Architect
- UX Research Lead
- Accessibility Specialist
- Product Manager
**Responsibilities:**
- Approve architecture changes
- Set design system roadmap
- Resolve escalated decisions
- Budget allocation
**Meeting Schedule:** Monthly
### CSS Working Group
**Role:** Technical implementation and standards
**Members:**
- Senior Frontend Engineers (3-5)
- CSS Specialist
- Performance Engineer
- Quality Assurance Lead
**Responsibilities:**
- Review RFCs (Request for Comments)
- Define coding standards
- Approve new components
- Maintain documentation
**Meeting Schedule:** Weekly
### Component Owners
**Role:** Individual component maintenance
**Responsibilities:**
- Implement features
- Fix bugs
- Update documentation
- Review PRs for owned components
**Assignment:** Each component has 1 primary + 1 secondary owner
### Quality Assurance Team
**Role:** Testing and validation
**Responsibilities:**
- Visual regression testing
- Accessibility audits
- Performance testing
- Cross-browser validation
## 2. Decision Making Process
### RFC (Request for Comments) Process
**When to Create RFC:**
- New architecture patterns
- Breaking changes
- New major components
- Methodology changes
- Performance budget adjustments
**RFC Template:**
```markdown
# RFC: [Title]
**Date:** YYYY-MM-DD
**Author:** Name
**Status:** Draft | Review | Approved | Rejected
## Summary
Brief description (2-3 sentences)
## Motivation
Why is this needed?
## Detailed Design
Technical implementation details
## Drawbacks
Potential downsides and risks
## Alternatives
What other approaches were considered?
## Migration Plan
How to adopt this change?
## Performance Impact
Expected performance implications
Review Timeline:
- Week 1: RFC submission
- Week 2-3: Working Group review and discussion
- Week 4: POC implementation (if needed)
- Week 5: Council approval for major changes
- Week 6+: Implementation with migration plan
Decision Escalation Path
- Component Owner → Lead Engineer
- Lead Engineer → CSS Working Group
- CSS Working Group → Design System Council
- Council decision is final
3. Code Standards
Mandatory Requirements
Linting:
- All CSS must pass Stylelint with zero warnings
- Configuration:
.stylelintrc.json in repository root
- Pre-commit hooks enforce linting
Documentation:
- Every component requires documentation
- Storybook stories for all UI components
- Usage examples and API documentation
- Accessibility notes
Performance:
- CSS bundle size budget: 250KB (uncompressed)
- Critical CSS budget: 14KB (inline)
- Specificity maximum: 0-3-0
- No !important except in utilities
Accessibility:
- WCAG 2.1 AA minimum compliance
- Focus indicators on all interactive elements
- Color contrast ratios meet guidelines
- Screen reader testing required
Browser Support:
- Chrome: Last 2 versions
- Firefox: Last 2 versions
- Safari: Last 2 versions
- Edge: Last 2 versions
- Mobile Safari: Last 2 versions
Code Quality Metrics
Tracked Metrics:
- Bundle size (gzipped and uncompressed)
- Number of selectors
- Specificity distribution
- Unused CSS percentage
- Critical CSS size
- Parse time (performance)
- Paint time (performance)
Quality Gates:
- Code coverage > 80%
- Visual regression: 0 unreviewed changes
- Accessibility: 0 violations
- Performance budget: Must meet all budgets
4. Review Requirements
Pull Request Requirements
Required Checks (Automated):
- ✅ Stylelint passes
- ✅ Build succeeds
- ✅ Visual regression tests pass
- ✅ Performance budgets met
- ✅ No accessibility violations
Required Reviews:
- 2 peer approvals for standard changes
- Design System team approval for new components
- Performance team approval for bundles > 50KB
- Accessibility team approval for interactive components
Review Checklist:
## Architecture
- [ ] Follows established patterns
- [ ] Appropriate file location
- [ ] Correct naming conventions
## Code Quality
- [ ] No !important (except utilities)
- [ ] Uses design tokens
- [ ] Minimal nesting (max 3 levels)
- [ ] DRY principle followed
## Performance
- [ ] Efficient selectors
- [ ] No layout thrashing
- [ ] Critical CSS identified
## Documentation
- [ ] Component docs complete
- [ ] Usage examples provided
- [ ] Changelog updated
## Testing
- [ ] Visual regression passes
- [ ] Accessibility tested
- [ ] Cross-browser verified
5. Compliance & Enforcement
Automated Enforcement:
- Pre-commit hooks for linting
- CI/CD pipeline blocks failing builds
- Automated performance budgets
Manual Review:
- Design review for visual QA
- Accessibility audit for new features
- Architecture review for major changes
Violation Process:
- Warning: First violation - educational feedback
- Required Fix: Second violation - must fix before merge
- Escalation: Repeated violations - team lead involvement
6. Training & Onboarding
New Team Members:
- 2-week onboarding program
- Pair programming sessions
- Documentation review
- Small starter tasks
Ongoing Education:
- Weekly CSS learning sessions
- Monthly architecture reviews
- Quarterly workshops
- Annual conference attendance budget
7. Documentation Standards
Required Documentation:
- Architecture Decision Records (ADRs)
- Component API documentation
- Usage guidelines
- Migration guides
- Performance notes
- Accessibility requirements
Documentation Locations:
- Storybook: Component documentation
- Confluence: Architecture decisions
- README: Getting started
- Wiki: Detailed guides
### Code Review Checklist
```scss
/**
* Enterprise CSS Code Review Checklist
* @description Comprehensive review criteria for CSS contributions
* @version 2.1.0
* @governance Mandatory for all CSS changes
*/
// ===== ARCHITECTURE COMPLIANCE =====
/**
* Architecture Review
* @checklist
* - [ ] Follows ITCSS/Atomic/established architecture
* - [ ] Correct layer placement (Settings/Tools/Components/etc)
* - [ ] File naming follows conventions
* - [ ] Appropriate directory structure
* - [ ] No cross-layer violations
*/
// ===== NAMING CONVENTIONS =====
/**
* Naming Standards
* @checklist
* - [ ] BEM methodology followed consistently
* - [ ] Namespace prefix used correctly
* - [ ] Class names are semantic and meaningful
* - [ ] No abbreviations (except standard: btn, nav)
* - [ ] Modifier naming is clear
*/
// ===== CODE QUALITY =====
/**
* Code Quality Standards
* @checklist
* - [ ] No !important (except in utility layer)
* - [ ] No magic numbers (all values use variables/tokens)
* - [ ] Mixins used appropriately
* - [ ] Functions used for calculations
* - [ ] DRY principle applied
* - [ ] Consistent code formatting
* - [ ] Logical properties used (margin-inline vs margin-left)
*/
// Example of quality issues:
// ❌ BAD
.card {
margin-left: 16px; // Magic number + physical property
color: #333 !important; // Unnecessary !important
.title {
.text {
.inner {
// Too much nesting
}
}
}
}
// ✅ GOOD
.card {
margin-inline-start: var(--spacing-md); // Token + logical property
color: var(--color-text-primary);
&__title {
// Single level nesting
}
}
// ===== PERFORMANCE =====
/**
* Performance Standards
* @checklist
* - [ ] Specificity kept low (max 0-3-0)
* - [ ] Nesting limited to 3 levels
* - [ ] Efficient selectors (avoid universal, descendant)
* - [ ] Critical CSS identified and extracted
* - [ ] No expensive properties (box-shadow on scroll)
* - [ ] Bundle size impact measured
* - [ ] No redundant selectors
*/
// Performance budget check
/**
* Bundle Size Impact
* @metric Current: 45KB | After Change: 47KB | Budget: 50KB
* @status ✅ Within budget
*/
// ===== DESIGN TOKENS =====
/**
* Design Token Usage
* @checklist
* - [ ] All colors use design tokens
* - [ ] All spacing uses spacing scale
* - [ ] Typography tokens applied
* - [ ] No hard-coded values
* - [ ] Semantic tokens preferred over primitive
* - [ ] Component tokens for specific use cases
*/
// ===== ACCESSIBILITY =====
/**
* Accessibility Requirements
* @checklist
* - [ ] Color contrast meets WCAG 2.1 AA (4.5:1 text, 3:1 UI)
* - [ ] Focus indicators visible and meet standards
* - [ ] Interactive elements have hover/focus/active states
* - [ ] No reliance on color alone for information
* - [ ] Text is resizable up to 200%
* - [ ] Reduced motion respected (@media prefers-reduced-motion)
* - [ ] High contrast mode supported
*/
// Example accessibility checks:
// ✅ GOOD - Contrast ratio: 7.2:1 (AAA)
.button {
background: var(--color-primary); // #0d47a1
color: #ffffff;
&:focus-visible {
outline: 2px solid var(--color-focus);
outline-offset: 2px;
}
}
// ❌ BAD - Contrast ratio: 2.8:1 (Fails AA)
.button-bad {
background: #90caf9; // Too light
color: #ffffff;
&:focus {
outline: none; // Removes focus indicator
}
}
// ===== RESPONSIVE DESIGN =====
/**
* Responsive Requirements
* @checklist
* - [ ] Mobile-first approach
* - [ ] Breakpoints use design tokens
* - [ ] Container queries where appropriate
* - [ ] Flexible units (rem, em, %) over px
* - [ ] Tested on all required viewports
* - [ ] No horizontal scrolling
*/
// ===== BROWSER COMPATIBILITY =====
/**
* Browser Support
* @checklist
* - [ ] Tested in Chrome (last 2 versions)
* - [ ] Tested in Firefox (last 2 versions)
* - [ ] Tested in Safari (last 2 versions)
* - [ ] Tested in Edge (last 2 versions)
* - [ ] Autoprefixer applied
* - [ ] Fallbacks for unsupported features
*/
// ===== DOCUMENTATION =====
/**
* Documentation Requirements
* @checklist
* - [ ] Component purpose documented
* - [ ] Usage examples provided
* - [ ] Props/modifiers documented
* - [ ] Storybook story created
* - [ ] Accessibility notes included
* - [ ] Browser support listed
* - [ ] Changelog updated
*/
// ===== TESTING =====
/**
* Testing Requirements
* @checklist
* - [ ] Visual regression tests created/updated
* - [ ] Accessibility tests pass (axe-core)
* - [ ] Cross-browser testing completed
* - [ ] Responsive testing done
* - [ ] Performance testing conducted
* - [ ] Interactive states tested
*/
// ===== DESIGN SYSTEM ALIGNMENT =====
/**
* Design System Compliance
* @checklist
* - [ ] Uses design tokens exclusively
* - [ ] Follows spacing system
* - [ ] Typography scale applied correctly
* - [ ] Color palette compliance
* - [ ] Adheres to grid system
* - [ ] Consistent with existing patterns
*/
// ===== MIGRATION & DEPRECATION =====
/**
* Breaking Changes
* @checklist (if applicable)
* - [ ] Migration guide provided
* - [ ] Deprecation warnings added
* - [ ] Version bump appropriate (MAJOR for breaking)
* - [ ] Backward compatibility considered
* - [ ] Codemods provided for automation
* - [ ] Communication plan defined
*/
Component Library Architecture
Component Template System
@mixin component-template($name, $config: ()) {
.c-#{$name} {
--#{$name}-background: var(--color-surface);
--#{$name}-color: var(--color-text);
--#{$name}-border: var(--border-default);
--#{$name}-padding: var(--spacing-md);
--#{$name}-border-radius: var(--radius-md);
--#{$name}-transition: var(--transition-default);
background: var(--#{$name}-background);
color: var(--#{$name}-color);
border: var(--#{$name}-border);
padding: var(--#{$name}-padding);
border-radius: var(--#{$name}-border-radius);
transition: var(--#{$name}-transition);
@content;
}
}
Complete Button Component Example
@include component-template('button', (
'category': 'Core Components',
'version': '2.1.0',
'status': 'stable',
'designer': 'Jane Doe',
'developer': 'John Smith',
'last-modified': '2024-01-15',
'accessibility': 'WCAG 2.1 AA - Keyboard accessible, ARIA support'
)) {
display: inline-flex;
align-items: center;
justify-content: center;
gap: var(--spacing-xs);
font-family: var(--font-family-primary);
font-weight: var(--font-weight-medium);
text-decoration: none;
cursor: pointer;
user-select: none;
white-space: nowrap;
&--small {
--button-padding: var(--spacing-xs) var(--spacing-sm);
--button-font-size: var(--font-size-sm);
--button-min-height: 32px;
}
&--medium {
--button-padding: var(--spacing-sm) var(--spacing-md);
--button-font-size: var(--font-size-base);
--button-min-height: 40px;
}
&--large {
--button-padding: var(--spacing-md) var(--spacing-lg);
--button-font-size: var(--font-size-lg);
--button-min-height: 48px;
}
&--primary {
--button-background: var(--color-primary);
--button-color: var(--color-primary-contrast);
&:hover:not(:disabled) {
--button-background: var(--color-primary-hover);
}
}
&--secondary {
--button-background: var(--color-secondary);
--button-color: var(--color-secondary-contrast);
&:hover:not(:disabled) {
--button-background: var(--color-secondary-hover);
}
}
&--outlined {
--button-background: transparent;
--button-color: var(--color-primary);
--button-border: 1px solid var(--color-primary);
&:hover:not(:disabled) {
--button-background: var(--color-primary-light);
}
}
&--text {
--button-background: transparent;
--button-color: var(--color-primary);
--button-border: none;
&:hover:not(:disabled) {
--button-background: var(--color-primary-light);
}
}
&:focus-visible {
outline: 2px solid var(--color-focus);
outline-offset: 2px;
}
&:active:not(:disabled) {
transform: translateY(1px);
}
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
&--loading {
position: relative;
color: transparent;
&::after {
content: '';
position: absolute;
width: 16px;
height: 16px;
border: 2px solid currentColor;
border-radius: 50%;
border-top-color: transparent;
animation: button-spin 0.6s linear infinite;
}
}
}
@keyframes button-spin {
to { transform: rotate(360deg); }
}
TypeScript Component Interface:
interface ButtonConfig {
variant: 'primary' | 'secondary' | 'outlined' | 'text';
size: 'small' | 'medium' | 'large';
disabled?: boolean;
loading?: boolean;
fullWidth?: boolean;
iconPosition?: 'left' | 'right';
}
function getButtonClasses(config: ButtonConfig): string {
const classes = ['c-button'];
classes.push(`c-button--${config.variant}`);
classes.push(`c-button--${config.size}`);
if (config.loading) classes.push('c-button--loading');
if (config.fullWidth) classes.push('c-button--full-width');
return classes.join(' ');
}
Versioning & Migration
Semantic Versioning for CSS
Description: Version management strategy for design system CSS following semver principles.
$design-system-version: '3.2.1';
@mixin deprecate($message, $version-removed) {
@warn "DEPRECATION WARNING: #{$message}. This will be removed in version #{$version-removed}. Current version: #{$design-system-version}";
}
.btn {
@include deprecate(
"Use .c-button instead of .btn",
"4.0.0"
);
@extend .c-button;
}
$feature-flags: (
'css-custom-properties': true,
'container-queries': false,
'cascade-layers': false,
'logical-properties': true,
'has-selector': false
);
@function feature-enabled($feature) {
@return map-get($feature-flags, $feature) == true;
}
@if feature-enabled('css-custom-properties') {
:root {
--spacing-unit: 8px;
--color-primary: #007bff;
}
.component {
padding: var(--spacing-unit);
color: var(--color-primary);
}
} @else {
.component {
padding: 8px;
color: #007bff;
}
}
Migration Helper Utilities
@mixin compatibility-mode($from-version: '2.0') {
@if $from-version == '2.0' {
.btn { @extend .c-button; }
.btn-primary { @extend .c-button--primary; }
.btn-secondary { @extend .c-button--secondary; }
.card { @extend .c-card; }
.card-header { @extend .c-card__header; }
.card-body { @extend .c-card__body; }
.modal { @extend .c-modal; }
.modal-content { @extend .c-modal__content; }
@warn "Running in compatibility mode for v2.0. Please migrate to v3.0 class names.";
}
}
@mixin progressive-enhancement($feature) {
@if $feature == 'grid' {
@supports (display: grid) {
@content;
}
}
@if $feature == 'custom-properties' {
@supports (--css: variables) {
@content;
}
}
@if $feature == 'container-queries' {
@supports (container-type: inline-size) {
@content;
}
}
}
.layout {
display: flex;
flex-wrap: wrap;
@include progressive-enhancement('grid') {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}
}
TypeScript Migration Tools:
class MigrationManager {
private currentVersion: string;
private targetVersion: string;
createMigrationPlan(from: string, to: string): MigrationStep[] {
const steps: MigrationStep[] = [];
const [fromMajor, fromMinor] = from.split('.').map(Number);
const [toMajor, toMinor] = to.split('.').map(Number);
if (toMajor > fromMajor) {
steps.push({
type: 'breaking',
description: 'Update class names to new convention',
automated: true,
codemod: 'migrate-class-names.js'
});
steps.push({
type: 'breaking',
description: 'Update design token references',
automated: true,
codemod: 'migrate-tokens.js'
});
steps.push({
type: 'manual',
description: 'Review and test components',
automated: false
});
}
if (toMinor > fromMinor) {
steps.push({
type: 'additive',
description: 'Opt-in to new features',
automated: false
});
}
return steps;
}
generateReport(steps: MigrationStep[]): string {
let report = `# Migration Plan: ${this.currentVersion} → ${this.targetVersion}\n\n`;
report += `## Summary\n`;
report += `- Total steps: ${steps.length}\n`;
report += `- Automated: ${steps.filter(s => s.automated).length}\n`;
report += `- Manual: ${steps.filter(s => !s.automated).length}\n\n`;
report += `## Steps\n\n`;
steps.forEach((step, index) => {
report += `### ${index + 1}. ${step.description}\n`;
report += `**Type:** ${step.type}\n`;
report += `**Automated:** ${step.automated ? 'Yes' : 'No'}\n`;
if (step.codemod) {
report += `**Codemod:** \`${step.codemod}\`\n`;
}
report += `\n`;
});
return report;
}
}
interface MigrationStep {
type: 'breaking' | 'additive' | 'manual';
description: string;
automated: boolean;
codemod?: string;
}
Monorepo CSS Management
Monorepo Structure
Description: CSS organization and sharing strategy for monorepo environments with multiple applications.
enterprise-monorepo/
├── packages/
│ ├── design-system/ # Shared design system package
│ │ ├── src/
│ │ │ ├── tokens/ # Design tokens
│ │ │ │ ├── colors.scss
│ │ │ │ ├── typography.scss
│ │ │ │ └── spacing.scss
│ │ │ ├── foundation/ # Base utilities
│ │ │ │ ├── reset.scss
│ │ │ │ ├── mixins.scss
│ │ │ │ └── grid.scss
│ │ │ ├── components/ # UI components
│ │ │ │ ├── button/
│ │ │ │ ├── card/
│ │ │ │ └── modal/
│ │ │ └── index.scss # Main entry point
│ │ ├── dist/ # Built CSS
│ │ │ ├── design-system.css
│ │ │ ├── design-system.min.css
│ │ │ └── tokens.json
│ │ ├── package.json
│ │ └── README.md
│ │
│ ├── shared-components/ # Shared React/Angular components
│ │ └── src/
│ │ └── styles/
│ │ └── component-overrides.scss
│ │
│ ├── app-customer-portal/ # Application 1
│ │ └── src/
│ │ └── styles/
│ │ ├── main.scss # Imports design system
│ │ ├── theme.scss # App-specific theme
│ │ └── overrides/ # Component customizations
│ │
│ ├── app-admin-dashboard/ # Application 2
│ │ └── src/
│ │ └── styles/
│ │ ├── main.scss
│ │ ├── theme.scss
│ │ └── overrides/
│ │
│ └── app-marketing-site/ # Application 3
│ └── src/
│ └── styles/
│ ├── main.scss
│ ├── theme.scss
│ └── overrides/
│
├── tools/
│ ├── build-css/ # Shared build scripts
│ └── css-linter/ # Linting configuration
│
└── package.json # Root package.json
Shared Design System Package
@import 'tokens/colors';
@import 'tokens/typography';
@import 'tokens/spacing';
@import 'tokens/shadows';
@import 'tokens/breakpoints';
@import 'foundation/reset';
@import 'foundation/mixins';
@import 'foundation/functions';
@import 'foundation/grid';
@import 'components/button/button';
@import 'components/card/card';
@import 'components/input/input';
@import 'components/modal/modal';
@import 'components/table/table';
@import 'utilities/spacing';
@import 'utilities/typography';
@import 'utilities/visibility';
Package Configuration:
{
"name": "@company/design-system",
"version": "3.2.1",
"description": "Enterprise design system CSS",
"main": "dist/design-system.css",
"style": "dist/design-system.css",
"sass": "src/index.scss",
"files": [
"dist",
"src"
],
"exports": {
".": {
"style": "./dist/design-system.css",
"sass": "./src/index.scss",
"default": "./dist/design-system.css"
},
"./tokens": {
"sass": "./src/tokens/index.scss",
"json": "./dist/tokens.json"
},
"./components/*": {
"sass": "./src/components/*/index.scss"
}
},
"scripts": {
"build": "npm run build:css && npm run build:tokens",
"build:css": "sass src/index.scss dist/design-system.css --style=expanded",
"build:css:min": "sass src/index.scss dist/design-system.min.css --style=compressed",
"build:tokens": "node scripts/build-tokens.js",
"lint": "stylelint 'src/**/*.scss'",
"test": "npm run test:visual && npm run test:a11y",
"test:visual": "backstop test",
"test:a11y": "pa11y-ci"
},
"peerDependencies": {
"sass": "^1.69.0"
},
"devDependencies": {
"sass": "^1.69.0",
"stylelint": "^15.10.0",
"backstopjs": "^6.2.0",
"pa11y-ci": "^3.0.0"
}
}
Application Import Strategy
@use '@company/design-system' as ds;
@use '@company/design-system/tokens' as tokens;
@import 'theme';
@import 'overrides/button';
@import 'overrides/card';
@import 'overrides/navigation';
@import 'layouts/dashboard';
@import 'layouts/auth';
@import 'pages/home';
@import 'pages/profile';
Application Theme Customization:
:root {
--color-primary: #1a73e8;
--color-primary-hover: #1557b0;
--color-app-header: #1f2937;
--color-app-sidebar: #111827;
--app-header-height: 64px;
--app-sidebar-width: 280px;
}
.c-button--primary {
}
Shared Build Configuration
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const PostCSSPresetEnv = require('postcss-preset-env');
function createCSSConfig(options = {}) {
const isProduction = options.mode === 'production';
return {
module: {
rules: [
{
test: /\.(scss|sass)$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
sourceMap: !isProduction,
modules: {
auto: true,
localIdentName: isProduction
? '[hash:base64:8]'
: '[name]__[local]--[hash:base64:5]'
},
importLoaders: 2
}
},
{
loader: 'postcss-loader',
options: {
sourceMap: !isProduction,
postcssOptions: {
plugins: [
PostCSSPresetEnv({
stage: 3,
features: {
'nesting-rules': true,
'custom-properties': true,
'custom-media-queries': true,
'logical-properties-and-values': true
},
autoprefixer: {
grid: true
}
}),
...(isProduction ? [
require('@fullhuman/postcss-purgecss')({
content: [
'./src/**/*.{html,ts,tsx,js,jsx}',
'./node_modules/@company/**/*.{html,ts,tsx,js,jsx}'
],
safelist: {
standard: [/^c-/, /^m-/, /^o-/, /^u-/],
deep: [/modal/, /tooltip/],
greedy: [/data-theme$/]
}
})
] : [])
]
}
}
},
{
loader: 'sass-loader',
options: {
sourceMap: !isProduction,
sassOptions: {
includePaths: [
'node_modules',
'../../node_modules'
],
precision: 5,
outputStyle: isProduction ? 'compressed' : 'expanded'
}
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: isProduction
? 'css/[name].[contenthash:8].css'
: 'css/[name].css',
chunkFilename: isProduction
? 'css/[name].[contenthash:8].chunk.css'
: 'css/[name].chunk.css'
})
],
optimization: {
minimizer: [
new CssMinimizerPlugin({
minimizerOptions: {
preset: [
'default',
{
discardComments: { removeAll: true },
normalizeWhitespace: true,
colormin: true,
minifyFontValues: true,
minifyGradients: true
}
]
}
})
]
}
};
}
module.exports = { createCSSConfig };
Usage in Application:
const { createCSSConfig } = require('../../tools/build-css/webpack.css.config');
const { merge } = require('webpack-merge');
module.exports = (env, argv) => {
const cssConfig = createCSSConfig({ mode: argv.mode });
return merge(cssConfig, {
entry: './src/main.ts',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash].js'
}
});
};
Team Workflows & CI/CD
GitHub Actions CSS Pipeline
name: CSS Pipeline
on:
pull_request:
paths:
- 'packages/design-system/**'
- 'packages/*/src/styles/**'
- '.github/workflows/css-pipeline.yml'
push:
branches:
- main
- develop
concurrency:
group: css-${{ github.ref }}
cancel-in-progress: true
jobs:
lint:
name: CSS Linting
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run Stylelint
run: npm run lint:css
- name: Check CSS formatting
run: npm run format:check:css
- name: Validate design tokens
run: npm run validate:tokens
test:
name: CSS Testing
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build design system
run: npm run build --workspace=@company/design-system
- name: Visual regression testing
run: npm run test:visual
- name: Accessibility testing
run: npm run test:a11y:css
- name: Upload visual regression results
if: failure()
uses: actions/upload-artifact@v3
with:
name: visual-regression-diffs
path: backstop_data/bitmaps_test
build:
name: Build & Analysis
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Build design system
run: npm run build --workspace=@company/design-system
- name: Build applications
run: npm run build:apps
- name: Analyze CSS bundle size
run: npm run analyze:css
- name: Check performance budgets
run: npm run budget:check
- name: Upload build artifacts
uses: actions/upload-artifact@v3
with:
name: css-bundles
path: |
packages/design-system/dist
packages/*/dist/css
- name: Comment bundle size on PR
if: github.event_name == 'pull_request'
uses: andresz1/size-limit-action@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
performance:
name: Performance Testing
runs-on: ubuntu-latest
needs: build
timeout-minutes: 10
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Download build artifacts
uses: actions/download-artifact@v3
with:
name: css-bundles
path: dist
- name: Run Lighthouse CI
run: |
npm install -g @lhci/cli
lhci autorun
- name: Check CSS parse time
run: npm run test:css:parse-time
publish:
name: Publish Design System
runs-on: ubuntu-latest
needs: [lint, test, build, performance]
if: github.ref == 'refs/heads/main'
timeout-minutes: 10
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
run: npm ci
- name: Build design system
run: npm run build --workspace=@company/design-system
- name: Publish to npm
run: npm publish --workspace=@company/design-system --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Create GitHub release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: v${{ steps.package-version.outputs.version }}
release_name: Design System v${{ steps.package-version.outputs.version }}
body_path: CHANGELOG.md
CSS Performance Budgets
[
{
"name": "Design System - Full Bundle",
"path": "packages/design-system/dist/design-system.css",
"limit": "250 KB",
"gzip": true
},
{
"name": "Design System - Minified",
"path": "packages/design-system/dist/design-system.min.css",
"limit": "50 KB",
"gzip": true
},
{
"name": "Critical CSS",
"path": "packages/design-system/dist/critical.css",
"limit": "14 KB",
"gzip": false
},
{
"name": "App - Customer Portal",
"path": "packages/app-customer-portal/dist/css/main.css",
"limit": "300 KB",
"gzip": true
},
{
"name": "App - Admin Dashboard",
"path": "packages/app-admin-dashboard/dist/css/main.css",
"limit": "280 KB",
"gzip": true
}
]
Storybook Documentation
Storybook Configuration
module.exports = {
stories: [
'../packages/design-system/src/**/*.stories.@(js|jsx|ts|tsx|mdx)',
'../packages/design-system/src/**/*.docs.mdx'
],
addons: [
'@storybook/addon-essentials',
'@storybook/addon-a11y',
'@storybook/addon-design-tokens',
'@storybook/addon-interactions',
'storybook-addon-pseudo-states',
'storybook-css-modules-preset',
'storybook-dark-mode'
],
framework: {
name: '@storybook/html-webpack5',
options: {}
},
features: {
buildStoriesJson: true,
cssVariables: true,
modernInlineRender: true
},
typescript: {
check: true,
reactDocgen: 'react-docgen-typescript'
},
staticDirs: ['../public'],
webpackFinal: async (config) => {
config.module.rules.push({
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
});
return config;
}
};
Storybook Preview Configuration:
import '../packages/design-system/dist/design-system.css';
export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/
},
expanded: true,
sort: 'requiredFirst'
},
viewport: {
viewports: {
mobile: {
name: 'Mobile',
styles: { width: '375px', height: '667px' },
type: 'mobile'
},
tablet: {
name: 'Tablet',
styles: { width: '768px', height: '1024px' },
type: 'tablet'
},
desktop: {
name: 'Desktop',
styles: { width: '1440px', height: '900px' },
type: 'desktop'
},
wide: {
name: 'Wide Desktop',
styles: { width: '1920px', height: '1080px' },
type: 'desktop'
}
}
},
docs: {
toc: {
title: 'Table of Contents',
headingSelector: 'h2, h3'
},
source: {
type: 'code',
language: 'html'
}
},
a11y: {
config: {
rules: [
{
id: 'color-contrast',
enabled: true
},
{
id: 'aria-required-attr',
enabled: true
}
]
}
},
design: {
type: 'figma',
allowFullscreen: true
}
};
export const decorators = [
(Story) => {
return `
<div class="sb-container" style="padding: 2rem;">
${Story()}
</div>
`;
}
];
export const globalTypes = {
theme: {
name: 'Theme',
description: 'Global theme for components',
defaultValue: 'light',
toolbar: {
icon: 'circlehollow',
items: [
{ value: 'light', title: 'Light', icon: 'sun' },
{ value: 'dark', title: 'Dark', icon: 'moon' },
{ value: 'high-contrast', title: 'High Contrast', icon: 'contrast' }
],
dynamicTitle: true
}
}
};
Component Story Template
<!-- Button.stories.mdx -->
import { Meta, Story, Canvas, ArgsTable, Source, Description } from '@storybook/addon-docs';
import { Button } from './Button';
<Meta
title="Components/Core/Button"
component={Button}
parameters={{
design: {
type: 'figma',
url: 'https://www.figma.com/file/xxx/Design-System?node-id=123'
},
docs: {
description: {
component: 'The Button component is a fundamental UI element for triggering actions and events.'
}
}
}}
argTypes={{
variant: {
control: { type: 'select' },
options: ['primary', 'secondary', 'outlined', 'text'],
description: 'Button visual variant',
table: {
type: { summary: 'string' },
defaultValue: { summary: 'primary' }
}
},
size: {
control: { type: 'radio' },
options: ['small', 'medium', 'large'],
description: 'Button size',
table: {
type: { summary: 'string' },
defaultValue: { summary: 'medium' }
}
},
disabled: {
control: { type: 'boolean' },
description: 'Disabled state',
table: {
type: { summary: 'boolean' },
defaultValue: { summary: 'false' }
}
},
loading: {
control: { type: 'boolean' },
description: 'Loading state with spinner',
table: {
type: { summary: 'boolean' },
defaultValue: { summary: 'false' }
}
}
}}
/>
# Button Component
The Button component provides a clickable interface element for user interactions.
## Design Principles
- **Clarity**: Clear visual hierarchy with distinct variants
- **Accessibility**: Fully keyboard navigable with screen reader support
- **Consistency**: Follows enterprise design system guidelines
- **Flexibility**: Multiple variants and sizes for different contexts
## Usage Guidelines
### When to Use
- **Primary actions**: Main call-to-action on pages or in dialogs
- **Secondary actions**: Supporting actions with lower emphasis
- **Form submissions**: Submit or cancel form data
- **Navigation triggers**: Open dialogs, panels, or navigate
### When NOT to Use
- **Navigation between pages**: Use Link component instead
- **Toggle states**: Use Switch or Checkbox components
- **Multiple selections**: Use Checkbox or Radio groups
---
## Examples
### Primary Button
The primary button is for the main action on a page or section.
<Canvas>
<Story name="Primary">
{`
<button class="c-button c-button--primary c-button--medium">
Primary Action
</button>
`}
</Story>
</Canvas>
### Secondary Button
Secondary buttons are for supporting actions with less emphasis.
<Canvas>
<Story name="Secondary">
{`
<button class="c-button c-button--secondary c-button--medium">
Secondary Action
</button>
`}
</Story>
</Canvas>
### Button Sizes
Buttons come in three sizes: small, medium, and large.
<Canvas>
<Story name="Sizes">
{`
<div style="display: flex; gap: 1rem; align-items: center;">
<button class="c-button c-button--primary c-button--small">
Small
</button>
<button class="c-button c-button--primary c-button--medium">
Medium
</button>
<button class="c-button c-button--primary c-button--large">
Large
</button>
</div>
`}
</Story>
</Canvas>
### Button with Icon
Buttons can include icons for better context.
<Canvas>
<Story name="With Icon">
{`
<button class="c-button c-button--primary c-button--medium">
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
<path d="M8 0l8 8-8 8-8-8 8-8z"/>
</svg>
<span>With Icon</span>
</button>
`}
</Story>
</Canvas>
### Loading State
Buttons show a loading spinner when an action is in progress.
<Canvas>
<Story name="Loading">
{`
<button class="c-button c-button--primary c-button--medium c-button--loading">
Loading...
</button>
`}
</Story>
</Canvas>
### Disabled State
Disabled buttons cannot be interacted with.
<Canvas>
<Story name="Disabled">
{`
<button class="c-button c-button--primary c-button--medium" disabled>
Disabled Button
</button>
`}
</Story>
</Canvas>
---
## CSS Implementation
<Source
language="scss"
dark
code={`
/**
* Button Component
* @component c-button
* @version 2.1.0
*/
.c-button {
// Base styles
display: inline-flex;
align-items: center;
justify-content: center;
gap: var(--spacing-xs);
padding: var(--button-padding);
background: var(--button-background);
color: var(--button-color);
border: var(--button-border, none);
border-radius: var(--button-border-radius);
font-size: var(--button-font-size);
font-weight: var(--font-weight-medium);
font-family: inherit;
line-height: 1;
text-decoration: none;
cursor: pointer;
user-select: none;
transition: all 0.2s ease;
// Variants
&--primary {
--button-background: var(--color-primary);
--button-color: var(--color-primary-contrast);
}
&--secondary {
--button-background: var(--color-secondary);
--button-color: var(--color-secondary-contrast);
}
// Sizes
&--small {
--button-padding: var(--spacing-xs) var(--spacing-sm);
--button-font-size: var(--font-size-sm);
}
&--medium {
--button-padding: var(--spacing-sm) var(--spacing-md);
--button-font-size: var(--font-size-base);
}
&--large {
--button-padding: var(--spacing-md) var(--spacing-lg);
--button-font-size: var(--font-size-lg);
}
// States
&:focus-visible {
outline: 2px solid var(--color-focus);
outline-offset: 2px;
}
&:hover:not(:disabled) {
filter: brightness(1.1);
}
&:active:not(:disabled) {
transform: translateY(1px);
}
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
}
`}
/>
---
## Accessibility
### WCAG 2.1 AA Compliance
- ✅ **Color Contrast**: Meets 4.5:1 ratio for text
- ✅ **Keyboard Navigation**: Fully accessible via Tab and Enter/Space
- ✅ **Focus Indicators**: Visible 2px outline with 2px offset
- ✅ **Screen Reader**: Proper ARIA labels and states
### Keyboard Shortcuts
| Key | Action |
|-----|--------|
| Tab | Focus button |
| Enter | Activate button |
| Space | Activate button |
### ARIA Attributes
```html
<button
class="c-button c-button--primary"
aria-label="Submit form"
aria-disabled="false"
aria-busy="false">
Submit
</button>
Browser Support
| Browser | Version |
|---|
| Chrome | Last 2 |
| Firefox | Last 2 |
| Safari | Last 2 |
| Edge | Last 2 |
Props & API
Related Components
- Link: For navigation between pages
- IconButton: Button with only an icon
- ButtonGroup: Group of related buttons
Changelog
Version 2.1.0 (2024-01-15)
- Added loading state with spinner
- Improved focus indicators
- Enhanced accessibility with ARIA attributes
Version 2.0.0 (2023-12-01)
- BREAKING: Renamed
.btn to .c-button
- Added outlined and text variants