0
# Higher-Order Component API
1
2
The Higher-Order Component (HOC) API provides the classic React pattern for injecting styles into components as a `classes` prop. This approach is ideal for class components and when following traditional HOC patterns.
3
4
## Capabilities
5
6
### withStyles Function
7
8
Creates a higher-order component that injects styles as a `classes` prop into the wrapped component.
9
10
```typescript { .api }
11
/**
12
* Creates a higher-order component that injects styles as classes prop
13
* @param styles - JSS styles object or function that returns styles
14
* @param options - Configuration options for the HOC
15
* @returns HOC function that wraps components with injected styles
16
*/
17
function withStyles<ClassNames extends string | number | symbol, Props, Theme>(
18
styles: Styles<ClassNames, Props, Theme> | ((theme: Theme) => Styles<ClassNames, Props, undefined>),
19
options?: WithStylesOptions
20
): <C>(component: C) => ComponentType<
21
JSX.LibraryManagedAttributes<
22
C,
23
Omit<GetProps<C>, 'classes'> & {
24
classes?: Partial<ClassesForStyles<typeof styles>>;
25
innerRef?: RefObject<any> | ((instance: any) => void);
26
}
27
>
28
>;
29
30
interface WithStylesOptions extends BaseOptions {
31
/** Whether to inject theme as a prop to the wrapped component */
32
injectTheme?: boolean;
33
/** Custom JSS instance to use for this component */
34
jss?: Jss;
35
}
36
```
37
38
**Usage Examples:**
39
40
```typescript
41
import React from 'react';
42
import { withStyles } from 'react-jss';
43
44
// Static styles
45
const styles = {
46
button: {
47
padding: '10px 20px',
48
backgroundColor: '#007bff',
49
color: 'white',
50
border: 'none',
51
borderRadius: '4px',
52
cursor: 'pointer',
53
'&:hover': {
54
backgroundColor: '#0056b3'
55
}
56
}
57
};
58
59
// Class component usage
60
class MyButton extends React.Component {
61
render() {
62
const { classes, children, ...props } = this.props;
63
return (
64
<button className={classes.button} {...props}>
65
{children}
66
</button>
67
);
68
}
69
}
70
71
const StyledButton = withStyles(styles)(MyButton);
72
73
// Functional component usage
74
const MyFunctionalButton = ({ classes, children, ...props }) => (
75
<button className={classes.button} {...props}>
76
{children}
77
</button>
78
);
79
80
const StyledFunctionalButton = withStyles(styles)(MyFunctionalButton);
81
```
82
83
### Dynamic Styles with Theme
84
85
Using function-based styles that respond to theme and props:
86
87
```typescript
88
import React from 'react';
89
import { withStyles, ThemeProvider } from 'react-jss';
90
91
const dynamicStyles = (theme) => ({
92
container: {
93
padding: '20px',
94
backgroundColor: theme.backgroundColor,
95
color: theme.textColor,
96
borderRadius: theme.borderRadius
97
},
98
title: {
99
fontSize: (props) => props.large ? '24px' : '18px',
100
fontWeight: theme.fontWeight.bold,
101
marginBottom: '16px'
102
}
103
});
104
105
const MyComponent = ({ classes, title, children }) => (
106
<div className={classes.container}>
107
<h2 className={classes.title}>{title}</h2>
108
{children}
109
</div>
110
);
111
112
const StyledComponent = withStyles(dynamicStyles)(MyComponent);
113
114
// Usage with theme
115
const theme = {
116
backgroundColor: '#f5f5f5',
117
textColor: '#333',
118
borderRadius: '8px',
119
fontWeight: {
120
bold: 600
121
}
122
};
123
124
function App() {
125
return (
126
<ThemeProvider theme={theme}>
127
<StyledComponent title="Hello" large>
128
Content here
129
</StyledComponent>
130
</ThemeProvider>
131
);
132
}
133
```
134
135
### Theme Injection
136
137
Automatically inject theme as a prop to the wrapped component:
138
139
```typescript
140
const styles = {
141
card: {
142
padding: '16px',
143
borderRadius: '8px',
144
boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
145
}
146
};
147
148
const Card = ({ classes, theme, children }) => (
149
<div
150
className={classes.card}
151
style={{ backgroundColor: theme.cardBackground }}
152
>
153
{children}
154
</div>
155
);
156
157
const StyledCard = withStyles(styles, { injectTheme: true })(Card);
158
```
159
160
### Custom Classes Override
161
162
Components wrapped with withStyles accept a `classes` prop to override specific style classes:
163
164
```typescript
165
const Button = withStyles({
166
root: {
167
padding: '10px',
168
backgroundColor: 'blue'
169
}
170
})(({ classes, children }) => (
171
<button className={classes.root}>{children}</button>
172
));
173
174
// Override specific classes
175
<Button classes={{ root: 'my-custom-button-class' }}>
176
Click me
177
</Button>
178
```
179
180
### Inner Ref Access
181
182
Access the ref of the wrapped component using `innerRef`:
183
184
```typescript
185
const Input = withStyles({
186
input: {
187
padding: '8px',
188
border: '1px solid #ccc'
189
}
190
})(React.forwardRef(({ classes, ...props }, ref) => (
191
<input className={classes.input} ref={ref} {...props} />
192
)));
193
194
function App() {
195
const inputRef = React.useRef();
196
197
const focusInput = () => {
198
inputRef.current?.focus();
199
};
200
201
return (
202
<div>
203
<Input innerRef={inputRef} />
204
<button onClick={focusInput}>Focus Input</button>
205
</div>
206
);
207
}
208
```
209
210
## Types
211
212
```typescript { .api }
213
interface WithStylesProps<S extends Styles<any, any, any> | ((theme: any) => Styles<any, any, undefined>)> {
214
/** Generated CSS class names object */
215
classes: ClassesForStyles<S>;
216
}
217
218
/** @deprecated Please use WithStylesProps instead */
219
type WithStyles<S extends Styles<any, any, any> | ((theme: any) => Styles<any, any, undefined>)> = WithStylesProps<S>;
220
221
type GetProps<C> = C extends ComponentType<infer P> ? P : never;
222
```