JSS integration with React providing CSS-in-JS styling solutions with theming support
—
The React JSS theme system provides comprehensive theming capabilities with providers, context access, and theme injection. It's essential for applications requiring consistent design systems and theme switching functionality.
Context provider that makes theme available to all child components.
/**
* Theme context provider component
* Makes theme available to all child components via React context
*/
const ThemeProvider: ComponentType<{
/** Theme object to provide to child components */
theme: any;
/** Child components that will receive theme context */
children: ReactNode;
}>;Usage Examples:
import React from 'react';
import { ThemeProvider, createUseStyles } from 'react-jss';
const theme = {
colors: {
primary: '#007bff',
secondary: '#6c757d',
success: '#28a745',
danger: '#dc3545',
warning: '#ffc107',
info: '#17a2b8',
light: '#f8f9fa',
dark: '#343a40',
white: '#ffffff',
text: '#212529',
background: '#ffffff'
},
spacing: {
xs: '4px',
sm: '8px',
md: '16px',
lg: '24px',
xl: '32px',
xxl: '48px'
},
typography: {
fontFamily: '"Segoe UI", Tahoma, Geneva, Verdana, sans-serif',
fontSize: {
xs: '12px',
sm: '14px',
md: '16px',
lg: '18px',
xl: '20px',
xxl: '24px'
},
fontWeight: {
light: 300,
normal: 400,
medium: 500,
semibold: 600,
bold: 700
},
lineHeight: {
tight: 1.25,
normal: 1.5,
relaxed: 1.75
}
},
breakpoints: {
sm: '576px',
md: '768px',
lg: '992px',
xl: '1200px'
},
borderRadius: {
sm: '4px',
md: '8px',
lg: '12px',
xl: '16px'
},
shadows: {
sm: '0 1px 3px rgba(0,0,0,0.1)',
md: '0 4px 6px rgba(0,0,0,0.1)',
lg: '0 10px 25px rgba(0,0,0,0.1)',
xl: '0 20px 40px rgba(0,0,0,0.1)'
}
};
function App() {
return (
<ThemeProvider theme={theme}>
<MainContent />
</ThemeProvider>
);
}React hook to access the current theme from context.
/**
* Hook to access current theme from context
* @returns Current theme object from ThemeProvider
*/
function useTheme<T = DefaultTheme>(): T;Usage Examples:
import React from 'react';
import { useTheme, createUseStyles } from 'react-jss';
const useStyles = createUseStyles({
container: {
padding: '20px',
borderRadius: '8px'
}
});
function ThemedComponent() {
const theme = useTheme();
const classes = useStyles();
return (
<div
className={classes.container}
style={{
backgroundColor: theme.colors.background,
color: theme.colors.text,
fontFamily: theme.typography.fontFamily
}}
>
<h1 style={{ color: theme.colors.primary }}>
Themed Component
</h1>
<p style={{ fontSize: theme.typography.fontSize.md }}>
This component uses theme values directly.
</p>
</div>
);
}HOC that injects theme as a prop into the wrapped component.
/**
* Higher-order component that injects theme as prop
* @param component - Component to wrap with theme injection
* @returns Component with theme prop injected
*/
function withTheme<P>(component: ComponentType<P>): ComponentType<P & {theme: any}>;Usage Examples:
import React from 'react';
import { withTheme } from 'react-jss';
const Button = ({ theme, children, variant = 'primary', ...props }) => {
const backgroundColor = theme.colors[variant] || theme.colors.primary;
return (
<button
style={{
padding: theme.spacing.md,
backgroundColor,
color: theme.colors.white,
border: 'none',
borderRadius: theme.borderRadius.md,
fontSize: theme.typography.fontSize.md,
fontWeight: theme.typography.fontWeight.medium,
cursor: 'pointer',
boxShadow: theme.shadows.sm,
transition: 'all 0.3s ease'
}}
{...props}
>
{children}
</button>
);
};
const ThemedButton = withTheme(Button);
// Usage
<ThemedButton variant="success">
Success Button
</ThemedButton>Creates a custom theming context and utilities for more advanced theming scenarios.
/**
* Creates custom theming context and utilities
* @param defaultTheme - Optional default theme object
* @returns Theming utilities object with custom context
*/
function createTheming<T>(defaultTheme?: T): Theming<T>;
interface Theming<Theme> {
/** Custom theme context */
context: Context<Theme>;
/** withTheme HOC using custom context */
withTheme: (component: ComponentType<any>) => ComponentType<any>;
/** useTheme hook using custom context */
useTheme: () => Theme;
/** ThemeProvider using custom context */
ThemeProvider: ComponentType<{theme: Theme; children: ReactNode}>;
}Usage Examples:
import React from 'react';
import { createTheming, createUseStyles } from 'react-jss';
// Create custom theming for a specific design system
const appTheming = createTheming({
brandColors: {
primary: '#ff6b6b',
secondary: '#4ecdc4',
accent: '#45b7d1'
},
spacing: {
small: '8px',
medium: '16px',
large: '24px'
}
});
const { ThemeProvider, useTheme, withTheme } = appTheming;
// Use the custom theming in styles
const useStyles = createUseStyles(
(theme) => ({
card: {
padding: theme.spacing.medium,
backgroundColor: theme.brandColors.primary,
borderRadius: '8px',
color: 'white'
}
}),
{ theming: appTheming }
);
function Card() {
const classes = useStyles();
const theme = useTheme();
return (
<div className={classes.card}>
<h3>Custom Themed Card</h3>
<p>Using brand color: {theme.brandColors.primary}</p>
</div>
);
}
function App() {
return (
<ThemeProvider theme={{
brandColors: {
primary: '#e74c3c',
secondary: '#3498db',
accent: '#f39c12'
},
spacing: {
small: '4px',
medium: '12px',
large: '20px'
}
}}>
<Card />
</ThemeProvider>
);
}Use theme directly in style definitions:
import React from 'react';
import { createUseStyles, ThemeProvider } from 'react-jss';
const useStyles = createUseStyles((theme) => ({
layout: {
fontFamily: theme.typography.fontFamily,
backgroundColor: theme.colors.background,
color: theme.colors.text,
minHeight: '100vh',
padding: theme.spacing.lg
},
header: {
backgroundColor: theme.colors.primary,
color: theme.colors.white,
padding: theme.spacing.md,
borderRadius: theme.borderRadius.md,
marginBottom: theme.spacing.lg,
boxShadow: theme.shadows.md,
'& h1': {
fontSize: theme.typography.fontSize.xxl,
fontWeight: theme.typography.fontWeight.bold,
margin: 0
}
},
content: {
backgroundColor: theme.colors.white,
padding: theme.spacing.lg,
borderRadius: theme.borderRadius.lg,
boxShadow: theme.shadows.sm,
'& p': {
fontSize: theme.typography.fontSize.md,
lineHeight: theme.typography.lineHeight.normal,
marginBottom: theme.spacing.md
}
},
button: {
backgroundColor: theme.colors.success,
color: theme.colors.white,
padding: `${theme.spacing.sm} ${theme.spacing.md}`,
border: 'none',
borderRadius: theme.borderRadius.sm,
fontSize: theme.typography.fontSize.md,
fontWeight: theme.typography.fontWeight.medium,
cursor: 'pointer',
boxShadow: theme.shadows.sm,
transition: 'all 0.3s ease',
'&:hover': {
backgroundColor: theme.colors.primary,
boxShadow: theme.shadows.md
}
}
}));
function ThemedLayout() {
const classes = useStyles();
return (
<div className={classes.layout}>
<header className={classes.header}>
<h1>Themed Application</h1>
</header>
<main className={classes.content}>
<p>This layout uses theme values for all styling.</p>
<button className={classes.button}>
Themed Button
</button>
</main>
</div>
);
}Implement theme switching functionality:
import React, { useState } from 'react';
import { ThemeProvider, createUseStyles } from 'react-jss';
const lightTheme = {
colors: {
background: '#ffffff',
text: '#333333',
primary: '#007bff',
surface: '#f8f9fa'
}
};
const darkTheme = {
colors: {
background: '#1a1a1a',
text: '#ffffff',
primary: '#0d6efd',
surface: '#2d2d2d'
}
};
const useStyles = createUseStyles((theme) => ({
app: {
backgroundColor: theme.colors.background,
color: theme.colors.text,
minHeight: '100vh',
padding: '20px',
transition: 'all 0.3s ease'
},
card: {
backgroundColor: theme.colors.surface,
padding: '20px',
borderRadius: '8px',
marginBottom: '20px'
},
button: {
backgroundColor: theme.colors.primary,
color: 'white',
padding: '10px 20px',
border: 'none',
borderRadius: '4px',
cursor: 'pointer'
}
}));
function ThemedApp() {
const [isDark, setIsDark] = useState(false);
const theme = isDark ? darkTheme : lightTheme;
const classes = useStyles();
return (
<ThemeProvider theme={theme}>
<div className={classes.app}>
<div className={classes.card}>
<h1>Theme Switching Example</h1>
<p>Current theme: {isDark ? 'Dark' : 'Light'}</p>
<button
className={classes.button}
onClick={() => setIsDark(!isDark)}
>
Switch to {isDark ? 'Light' : 'Dark'} Theme
</button>
</div>
</div>
</ThemeProvider>
);
}Define strongly typed themes with TypeScript:
import React from 'react';
import { ThemeProvider, createUseStyles } from 'react-jss';
// Define theme interface
interface AppTheme {
colors: {
primary: string;
secondary: string;
background: string;
text: string;
};
spacing: {
sm: string;
md: string;
lg: string;
};
typography: {
fontSize: {
sm: string;
md: string;
lg: string;
};
};
}
// Extend global theme interface
declare global {
namespace Jss {
interface Theme extends AppTheme {}
}
}
const theme: AppTheme = {
colors: {
primary: '#007bff',
secondary: '#6c757d',
background: '#ffffff',
text: '#333333'
},
spacing: {
sm: '8px',
md: '16px',
lg: '24px'
},
typography: {
fontSize: {
sm: '14px',
md: '16px',
lg: '20px'
}
}
};
const useStyles = createUseStyles<string, {}, AppTheme>((theme) => ({
container: {
padding: theme.spacing.md,
backgroundColor: theme.colors.background,
color: theme.colors.text
}
}));
function TypedThemedComponent() {
const classes = useStyles();
return (
<div className={classes.container}>
Strongly typed themed component
</div>
);
}type DefaultTheme = Jss.Theme;
interface Theming<Theme> {
context: Context<Theme>;
withTheme: (component: ComponentType<any>) => ComponentType<any>;
useTheme: () => Theme;
ThemeProvider: ComponentType<{theme: Theme; children: ReactNode}>;
}
declare global {
namespace Jss {
/** You can use the global Jss.Theme interface to define a project-wide default theme. */
export interface Theme {}
}
}Install with Tessl CLI
npx tessl i tessl/npm-react-jss