theme Service
The theme
service provides access to design tokens and theming utilities for styling components in Pinstripe applications. It manages a centralized theme configuration that includes colors, typography, spacing, breakpoints, and other design system values.
Interface
The theme service returns a deferred promise that resolves to a Theme instance with the following methods:
Core Methods
deepMerge(variables)
- Deeply merges additional design tokens into the themeresolveReferences()
- Resolves reference tokens (e.g.,@colors.red.500
) to their actual valuesgetNestedProperty(path)
- Gets a nested property value using dot notationbreakpointFor(minWidthProperty)
- Generates CSS media query for a breakpointremify(value)
- Converts pixel values to rem units (divides by 16)
Static Methods
Theme.defineDesignTokens(designTokens)
- Defines design tokens that are merged into all theme instances
Default Design Tokens
The theme service comes with comprehensive default design tokens including:
- Colors: Full color palette with 50-950 shades for each color (red, blue, green, etc.)
- Typography: Font families, sizes, weights, line heights, letter spacing
- Spacing: Base spacing unit and modular scale
- Breakpoints: Responsive breakpoints (sm, md, lg, xl, 2xl)
- Shadows: Box shadows, inset shadows, drop shadows, text shadows
- Borders: Border radius values
- Animations: Easing functions and keyframe animations
- Layout: Container sizes and aspect ratios
Usage
Basic Usage
Access the theme in views and services:
export default {
async render() {
const theme = await this.theme;
const primaryColor = theme.colors.blue[500];
return this.renderHtml`<div style="color: ${primaryColor}">Hello</div>`;
}
};
Using in Styles
The most common usage is in view styles where the theme is passed as a parameter:
export const styles = ({ colors, fonts, breakpoints }) => `
.header {
color: ${colors.semantic.primaryText};
font-family: ${fonts.sans};
background-color: ${colors.blue[50]};
border-bottom: 1px solid ${colors.gray[200]};
}
.accent {
color: ${colors.semantic.accent};
}
@media (min-width: ${breakpoints.md}) {
.header {
font-size: 2rem;
}
}
`;
Resolving References
Use reference tokens for consistency and easier theming:
export default {
async render() {
const theme = await this.theme.resolveReferences();
// If theme has { accent: "@colors.pink.600" }, this resolves to the actual color value
const accentColor = theme.accent;
return this.renderHtml`<div style="color: ${accentColor}">Accent text</div>`;
}
};
Custom Configuration
Configure custom theme values in your pinstripe.config.js
:
export default {
theme: {
colors: {
brand: {
primary: '#0066cc',
secondary: '#6c757d'
},
semantic: {
accent: '@colors.brand.primary'
}
},
fonts: {
display: 'Georgia, serif'
}
}
};
Breakpoint Utilities
Generate responsive CSS with breakpoint helpers:
export const styles = (theme) => `
.container {
width: 100%;
padding: 1rem;
}
${theme.breakpointFor('md')} {
.container {
max-width: ${theme.containers.lg};
margin: 0 auto;
}
}
`;
Utility Functions
Use built-in utility functions for common operations:
export const styles = (theme) => `
.spacing {
margin: ${theme.remify(32)}; /* Converts 32px to 2rem */
padding: ${theme.getNestedProperty('spacing')};
}
`;
Extending Themes
Add design tokens programmatically:
// In a service or initialization file
import { Theme } from 'pinstripe';
Theme.defineDesignTokens({
components: {
button: {
borderRadius: '@radius.md',
padding: '0.75rem 1.5rem'
}
}
});
Component-Specific Themes
Define component-specific design tokens that are automatically scoped:
// In a view file
export const theme = {
card: {
background: '@colors.white',
shadow: '@shadow.md',
radius: '@radius.lg'
}
};
export const styles = ({ views }) => `
.card {
background: ${views.components.card.background};
box-shadow: ${views.components.card.shadow};
border-radius: ${views.components.card.radius};
}
`;
Advanced Theme Customization
Create dynamic themes based on runtime conditions:
export default {
create() {
return this.defer(async () => {
const baseTheme = await this.config.theme || {};
const userPreferences = await this.getUserPreferences();
return Theme.new()
.deepMerge(baseTheme)
.deepMerge({
colors: {
semantic: {
accent: userPreferences.accentColor || '@colors.blue.600'
}
}
})
.resolveReferences();
});
}
};
Command Line Usage
View the current theme configuration:
pinstripe show_theme
This outputs the complete resolved theme as JSON, useful for debugging and understanding the current design token values.
Integration with Styling System
The theme service integrates seamlessly with Pinstripe's styling system:
- Style Functions: Theme is automatically passed to style functions as the first parameter
- Reference Resolution: The
@property.path
syntax automatically resolves to theme values - CSS Processing: Styles are processed through PostCSS with autoprefixing and optimization
- Component Scoping: CSS classes are automatically scoped to prevent naming conflicts
Best Practices
- Use Semantic Colors: Prefer semantic color names (
colors.semantic.accent
) over specific color values - Reference Tokens: Use reference tokens (
@colors.blue.500
) for consistency and easy theming - Responsive Design: Leverage breakpoint utilities for consistent responsive behavior
- Component Tokens: Define component-specific tokens for reusable styling patterns
- Configuration: Keep theme customizations in
pinstripe.config.js
for environment-specific theming
The theme service provides a powerful foundation for building consistent, maintainable, and customizable user interfaces in Pinstripe applications.