0
# Component Composition
1
2
Utilities for extending and modifying existing styled components with additional styles, transformations, and wrapper components. These functions enable composition and reuse of styled components.
3
4
## Capabilities
5
6
### With Style
7
8
Extends existing styled components with additional styles using deep merge.
9
10
```typescript { .api }
11
/**
12
* Extends existing styled components with additional styles using deep merge
13
* @param component - Existing styled component to extend
14
* @param style - Style object or function to merge with existing styles
15
* @returns New styled component with merged styles
16
*/
17
function withStyle<Base extends StyletronComponent<any, any>, Props = {}>(
18
component: Base,
19
style: StyleObject | ((props: Props) => StyleObject)
20
): Base extends StyletronComponent<infer D, infer P>
21
? StyletronComponent<D, P & Props>
22
: never;
23
```
24
25
**Usage Examples:**
26
27
```typescript
28
import { styled, withStyle } from "styletron-react";
29
30
// Base button component
31
const BaseButton = styled("button", {
32
padding: "8px 16px",
33
border: "none",
34
borderRadius: "4px",
35
fontSize: "14px",
36
":hover": {
37
opacity: 0.8,
38
},
39
});
40
41
// Extend with additional styles (static)
42
const PrimaryButton = withStyle(BaseButton, {
43
backgroundColor: "blue",
44
color: "white",
45
});
46
47
// Extend with dynamic styles
48
const ConditionalButton = withStyle<typeof BaseButton, {$danger: boolean}>(
49
BaseButton,
50
(props) => ({
51
backgroundColor: props.$danger ? "red" : "green",
52
color: "white",
53
})
54
);
55
56
// Deep merge example - hover styles are merged
57
const HoverButton = withStyle(BaseButton, {
58
backgroundColor: "purple",
59
":hover": {
60
backgroundColor: "darkpurple", // Merged with existing hover styles
61
},
62
});
63
```
64
65
### With Transform
66
67
Transforms styles of existing styled components using a transformation function.
68
69
```typescript { .api }
70
/**
71
* Transforms styles of existing styled components using a transformation function
72
* @param component - Existing styled component to transform
73
* @param transformer - Function that receives current style and props, returns new style
74
* @returns New styled component with transformed styles
75
*/
76
function withTransform<
77
Base extends StyletronComponent<any, any>,
78
Props,
79
>(
80
component: Base,
81
transformer: (style: StyleObject, props: Props) => StyleObject
82
): Base extends StyletronComponent<infer D, infer P>
83
? StyletronComponent<D, P & Props>
84
: never;
85
```
86
87
**Usage Examples:**
88
89
```typescript
90
import { styled, withTransform } from "styletron-react";
91
92
const BaseButton = styled("button", {
93
padding: "8px 16px",
94
backgroundColor: "blue",
95
color: "white",
96
});
97
98
// Transform existing styles based on props
99
const ScalableButton = withTransform(
100
BaseButton,
101
(style, props: {$scale: number}) => ({
102
...style,
103
transform: `scale(${props.$scale})`,
104
transformOrigin: "center",
105
})
106
);
107
108
// Conditional transformation
109
const ToggleButton = withTransform(
110
BaseButton,
111
(style, props: {$active: boolean}) => ({
112
...style,
113
backgroundColor: props.$active ? "green" : style.backgroundColor,
114
fontWeight: props.$active ? "bold" : "normal",
115
})
116
);
117
```
118
119
### With Wrapper
120
121
Wraps styled components with additional wrapper components for layout or behavior modifications.
122
123
```typescript { .api }
124
/**
125
* Wraps styled components with additional wrapper components
126
* @param component - Existing styled component to wrap
127
* @param wrapper - Function that receives the component and returns a wrapper component
128
* @returns New styled component with wrapper applied
129
*/
130
function withWrapper<Base extends StyletronComponent<any, any>, Props>(
131
component: Base,
132
wrapper: (
133
component: Base
134
) => React.ComponentType<Props & React.ComponentProps<Base>>
135
): Base extends StyletronComponent<infer D, infer P>
136
? StyletronComponent<D, P & Props>
137
: never;
138
```
139
140
**Usage Examples:**
141
142
```typescript
143
import { styled, withWrapper } from "styletron-react";
144
145
const BaseButton = styled("button", {
146
padding: "8px 16px",
147
backgroundColor: "blue",
148
color: "white",
149
});
150
151
// Wrap with container div
152
const ContainerButton = withWrapper(BaseButton, (StyledButton) => (props) => (
153
<div className="button-container">
154
<StyledButton {...props} />
155
</div>
156
));
157
158
// Wrap with loading state
159
const LoadingButton = withWrapper(
160
BaseButton,
161
(StyledButton) => (props: {$loading?: boolean} & React.ComponentProps<typeof BaseButton>) => (
162
<div style={{position: "relative"}}>
163
<StyledButton {...props} disabled={props.$loading || props.disabled}>
164
{props.$loading ? "Loading..." : props.children}
165
</StyledButton>
166
</div>
167
)
168
);
169
170
// Complex wrapper with additional functionality
171
const TooltipButton = withWrapper(
172
BaseButton,
173
(StyledButton) => (props: {$tooltip?: string} & React.ComponentProps<typeof BaseButton>) => (
174
<div title={props.$tooltip}>
175
<StyledButton {...props} />
176
</div>
177
)
178
);
179
```
180
181
## Composition Patterns
182
183
### Chaining Compositions
184
185
Multiple composition functions can be chained together:
186
187
```typescript
188
import { styled, withStyle, withTransform, withWrapper } from "styletron-react";
189
190
const BaseButton = styled("button", {
191
padding: "8px 16px",
192
border: "none",
193
});
194
195
// Chain multiple compositions
196
const EnhancedButton = withWrapper(
197
withTransform(
198
withStyle(BaseButton, {
199
backgroundColor: "blue",
200
color: "white",
201
}),
202
(style, props: {$size: "small" | "large"}) => ({
203
...style,
204
padding: props.$size === "large" ? "12px 24px" : "6px 12px",
205
})
206
),
207
(StyledButton) => (props) => (
208
<div className="button-wrapper">
209
<StyledButton {...props} />
210
</div>
211
)
212
);
213
```
214
215
### Style Inheritance
216
217
Compositions preserve and extend the type information and styling behavior:
218
219
```typescript
220
// All composition functions maintain prop types
221
const TypedButton = styled<"button", {$variant: "primary" | "secondary"}>("button", {
222
padding: "8px 16px",
223
});
224
225
// withStyle preserves and extends types
226
const ExtendedButton = withStyle<typeof TypedButton, {$size: "small" | "large"}>(
227
TypedButton,
228
(props) => ({
229
fontSize: props.$size === "large" ? "16px" : "14px",
230
backgroundColor: props.$variant === "primary" ? "blue" : "gray",
231
})
232
);
233
234
// Usage with full type safety
235
<ExtendedButton $variant="primary" $size="large">
236
Typed Button
237
</ExtendedButton>
238
```
239
240
## Types
241
242
```typescript { .api }
243
type WithStyleFn = {
244
<Base extends StyletronComponent<any, any>, Props = {}>(
245
component: Base,
246
style: StyleObject | ((props: Props) => StyleObject)
247
): Base extends StyletronComponent<infer D, infer P>
248
? StyletronComponent<D, P & Props>
249
: never;
250
};
251
252
type WithTransformFn = <
253
Base extends StyletronComponent<any, any>,
254
Props,
255
>(
256
component: Base,
257
style: (style: StyleObject, props: Props) => StyleObject
258
) => Base extends StyletronComponent<infer D, infer P>
259
? StyletronComponent<D, P & Props>
260
: never;
261
262
type WithWrapperFn = <Base extends StyletronComponent<any, any>, Props>(
263
component: Base,
264
wrapper: (
265
component: Base
266
) => React.ComponentType<Props & React.ComponentProps<Base>>
267
) => Base extends StyletronComponent<infer D, infer P>
268
? StyletronComponent<D, P & Props>
269
: never;
270
```