0
# Component System
1
2
Function-based component system with props utilities, lifecycle hooks, and component creation functions for building modular UI components.
3
4
## Capabilities
5
6
### Component Functions
7
8
Create and manage component instances with optimized rendering and lifecycle management.
9
10
```typescript { .api }
11
/**
12
* Creates a component instance
13
* @param Comp - Component function to instantiate
14
* @param props - Props to pass to the component
15
* @returns JSX element
16
*/
17
function createComponent<T extends Component<any>>(
18
Comp: T,
19
props: ComponentProps<T>
20
): JSX.Element;
21
22
/**
23
* Lazy load a function component asynchronously
24
* @param fn - Function that returns a promise with the component
25
* @returns Lazy component with preload capability
26
*/
27
function lazy<T extends Component<any>>(
28
fn: () => Promise<{ default: T }>
29
): T & { preload: () => Promise<{ default: T }> };
30
31
/**
32
* Creates a unique identifier for components
33
* @returns Unique string identifier
34
*/
35
function createUniqueId(): string;
36
```
37
38
**Usage Examples:**
39
40
```typescript
41
import { createComponent, lazy } from "solid-js";
42
43
// Creating component instances
44
function App() {
45
return createComponent(UserProfile, {
46
name: "John",
47
age: 30
48
});
49
}
50
51
// Lazy loading components
52
const LazyUserDashboard = lazy(() => import("./UserDashboard"));
53
54
function App() {
55
return (
56
<div>
57
<LazyUserDashboard userId="123" />
58
</div>
59
);
60
}
61
62
// Preloading lazy components
63
LazyUserDashboard.preload();
64
65
// Using unique IDs
66
function FormField() {
67
const id = createUniqueId();
68
return (
69
<div>
70
<label for={id}>Name:</label>
71
<input id={id} type="text" />
72
</div>
73
);
74
}
75
```
76
77
### Props Utilities
78
79
Merge and split props objects with reactive updates and type safety.
80
81
```typescript { .api }
82
/**
83
* Merges multiple props objects reactively
84
* @param sources - Props objects to merge
85
* @returns Merged props object
86
*/
87
function mergeProps<T extends Record<string, any>[]>(
88
...sources: T
89
): MergeProps<T>;
90
91
/**
92
* Splits props into multiple objects based on keys
93
* @param props - Props object to split
94
* @param keys - Arrays of keys to extract into separate objects
95
* @returns Array of split props objects
96
*/
97
function splitProps<T extends Record<string, any>, K extends (keyof T)[][]>(
98
props: T,
99
...keys: K
100
): SplitProps<T, K>;
101
102
type MergeProps<T extends Record<string, any>[]> = T extends [
103
infer First,
104
...infer Rest
105
]
106
? First & MergeProps<Rest>
107
: {};
108
109
type SplitProps<T, K> = K extends [infer First, ...infer Rest]
110
? First extends (keyof T)[]
111
? [Pick<T, First[number]>, ...SplitProps<Omit<T, First[number]>, Rest>]
112
: []
113
: [T];
114
```
115
116
**Usage Examples:**
117
118
```typescript
119
import { mergeProps, splitProps, createSignal } from "solid-js";
120
121
// Merging props
122
function Button(props) {
123
const merged = mergeProps(
124
{ type: "button", disabled: false },
125
props
126
);
127
128
return <button {...merged} />;
129
}
130
131
// Splitting props
132
function Input(props) {
133
const [inputProps, otherProps] = splitProps(props, ["value", "onInput", "placeholder"]);
134
135
return (
136
<div {...otherProps}>
137
<input {...inputProps} />
138
</div>
139
);
140
}
141
142
// Complex props handling
143
function CustomComponent(props) {
144
const [local, buttonProps, divProps] = splitProps(
145
props,
146
["label", "required"],
147
["onClick", "disabled"],
148
["class", "style"]
149
);
150
151
const defaultProps = { disabled: false, required: false };
152
const mergedLocal = mergeProps(defaultProps, local);
153
154
return (
155
<div {...divProps}>
156
{mergedLocal.required && <span>*</span>}
157
<label>{mergedLocal.label}</label>
158
<button {...buttonProps} disabled={mergedLocal.disabled || buttonProps.disabled}>
159
Click me
160
</button>
161
</div>
162
);
163
}
164
```
165
166
### Children Utilities
167
168
Resolve and interact with component children in reactive contexts.
169
170
```typescript { .api }
171
/**
172
* Resolves child elements to help interact with children
173
* @param fn - Accessor function that returns JSX children
174
* @returns Resolved children with helper methods
175
*/
176
function children(fn: Accessor<JSX.Element>): ChildrenReturn;
177
178
interface ChildrenReturn {
179
(): ResolvedJSXElement;
180
toArray(): ResolvedJSXElement[];
181
}
182
183
type ResolvedJSXElement = Element | Text | string | number;
184
```
185
186
**Usage Examples:**
187
188
```typescript
189
import { children, For } from "solid-js";
190
191
// Resolving children
192
function Container(props) {
193
const c = children(() => props.children);
194
195
return (
196
<div class="container">
197
<div class="header">Container has {c.toArray().length} children</div>
198
{c()}
199
</div>
200
);
201
}
202
203
// Working with children in custom components
204
function List(props) {
205
const c = children(() => props.children);
206
207
return (
208
<ul>
209
<For each={c.toArray()}>
210
{(child, index) => (
211
<li data-index={index()}>
212
{child}
213
</li>
214
)}
215
</For>
216
</ul>
217
);
218
}
219
220
// Usage
221
function App() {
222
return (
223
<Container>
224
<span>First child</span>
225
<span>Second child</span>
226
<span>Third child</span>
227
</Container>
228
);
229
}
230
```
231
232
## Component Types
233
234
### Basic Component Types
235
236
```typescript { .api }
237
/**
238
* A general Component has no implicit children prop
239
*/
240
type Component<P = {}> = (props: P) => JSX.Element;
241
242
/**
243
* Component that forbids children prop
244
*/
245
type VoidComponent<P = {}> = Component<VoidProps<P>>;
246
247
/**
248
* Component that allows optional children prop
249
*/
250
type ParentComponent<P = {}> = Component<ParentProps<P>>;
251
252
/**
253
* Component that requires children prop with specific type
254
*/
255
type FlowComponent<P, C> = Component<FlowProps<P, C>>;
256
```
257
258
### Props Types
259
260
```typescript { .api }
261
type VoidProps<P> = P & { children?: never };
262
type ParentProps<P> = P & { children?: JSX.Element };
263
type FlowProps<P, C> = P & { children: C };
264
265
type ComponentProps<T extends keyof JSX.IntrinsicElements | Component<any>> =
266
T extends Component<infer P>
267
? P
268
: T extends keyof JSX.IntrinsicElements
269
? JSX.IntrinsicElements[T]
270
: {};
271
```
272
273
### JSX Types
274
275
```typescript { .api }
276
declare namespace JSX {
277
type Element = any;
278
279
interface IntrinsicElements {
280
[elemName: string]: any;
281
}
282
283
interface ElementChildrenAttribute {
284
children: {};
285
}
286
}
287
```
288
289
## Advanced Patterns
290
291
### Higher-Order Components
292
293
```typescript
294
import { Component, createMemo } from "solid-js";
295
296
// HOC for adding loading state
297
function withLoading<P extends object>(
298
WrappedComponent: Component<P>
299
): Component<P & { loading?: boolean }> {
300
return (props) => {
301
const loading = createMemo(() => props.loading ?? false);
302
303
if (loading()) {
304
return <div>Loading...</div>;
305
}
306
307
return <WrappedComponent {...props} />;
308
};
309
}
310
311
// Usage
312
const UserProfileWithLoading = withLoading(UserProfile);
313
```
314
315
### Render Props Pattern
316
317
```typescript
318
import { Component, JSX } from "solid-js";
319
320
interface RenderPropsComponent<T> {
321
children: (data: T) => JSX.Element;
322
data: T;
323
}
324
325
function DataProvider<T>(props: RenderPropsComponent<T>): JSX.Element {
326
return <div>{props.children(props.data)}</div>;
327
}
328
329
// Usage
330
function App() {
331
return (
332
<DataProvider data={{ name: "John", age: 30 }}>
333
{(user) => (
334
<div>
335
<h1>{user.name}</h1>
336
<p>Age: {user.age}</p>
337
</div>
338
)}
339
</DataProvider>
340
);
341
}
342
```
343
344
### Component Composition
345
346
```typescript
347
import { ParentComponent, JSX } from "solid-js";
348
349
// Compound component pattern
350
const Card: ParentComponent & {
351
Header: ParentComponent;
352
Body: ParentComponent;
353
Footer: ParentComponent;
354
} = (props) => {
355
return <div class="card">{props.children}</div>;
356
};
357
358
Card.Header = (props) => <div class="card-header">{props.children}</div>;
359
Card.Body = (props) => <div class="card-body">{props.children}</div>;
360
Card.Footer = (props) => <div class="card-footer">{props.children}</div>;
361
362
// Usage
363
function App() {
364
return (
365
<Card>
366
<Card.Header>
367
<h2>Card Title</h2>
368
</Card.Header>
369
<Card.Body>
370
<p>Card content goes here.</p>
371
</Card.Body>
372
<Card.Footer>
373
<button>Action</button>
374
</Card.Footer>
375
</Card>
376
);
377
}
378
```