or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

component-system.mdcontext-scoping.mdcontrol-flow.mdindex.mdreactive-primitives.mdresources-async.mdstore-management.mdweb-rendering.md

component-system.mddocs/

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

```