or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced.mdcore.mdindex.mdjsx.mdmodules.md

advanced.mddocs/

0

# Advanced Features

1

2

Advanced Snabbdom features including performance optimization through thunks, comprehensive lifecycle hooks, and helper utilities for complex use cases.

3

4

## Capabilities

5

6

### Thunks

7

8

Thunks provide performance optimization by deferring virtual node creation until necessary, ideal for expensive computations with immutable data.

9

10

```typescript { .api }

11

/**

12

* Create a thunk for performance optimization

13

* @param sel - Element selector

14

* @param fn - Function that returns a virtual node

15

* @param args - Arguments passed to the function

16

* @returns Thunked virtual node

17

*/

18

function thunk(

19

sel: string,

20

fn: (...args: any[]) => any,

21

args: any[]

22

): VNode;

23

24

/**

25

* Create a thunk with a key for proper identification

26

* @param sel - Element selector

27

* @param key - Unique key for the thunk

28

* @param fn - Function that returns a virtual node

29

* @param args - Arguments passed to the function

30

* @returns Thunked virtual node

31

*/

32

function thunk(

33

sel: string,

34

key: any,

35

fn: (...args: any[]) => any,

36

args: any[]

37

): VNode;

38

```

39

40

**Usage Examples:**

41

42

```typescript

43

import { thunk, h, init } from "snabbdom";

44

45

// Expensive computation function

46

function createComplexView(data: any[]): VNode {

47

// This function is only called when data changes

48

return h("div.complex", data.map((item, i) =>

49

h("div.item", { key: i }, `Item: ${item.name}`)

50

));

51

}

52

53

// Using thunk to optimize

54

function render(state: { items: any[] }): VNode {

55

return h("div.app", [

56

h("h1", "My App"),

57

// Only re-renders when state.items changes

58

thunk("div.items", createComplexView, [state.items])

59

]);

60

}

61

62

// With key for sibling thunks

63

function renderWithKey(state: { users: any[], posts: any[] }): VNode {

64

return h("div.app", [

65

thunk("div.users", "users", createUsersList, [state.users]),

66

thunk("div.posts", "posts", createPostsList, [state.posts])

67

]);

68

}

69

```

70

71

### Lifecycle Hooks

72

73

Comprehensive hook system providing fine-grained control over the virtual DOM lifecycle.

74

75

```typescript { .api }

76

interface Hooks {

77

pre?: PreHook;

78

init?: InitHook;

79

create?: CreateHook;

80

insert?: InsertHook;

81

prepatch?: PrePatchHook;

82

update?: UpdateHook;

83

postpatch?: PostPatchHook;

84

destroy?: DestroyHook;

85

remove?: RemoveHook;

86

post?: PostHook;

87

}

88

89

type PreHook = () => any;

90

type InitHook = (vNode: VNode) => any;

91

type CreateHook = (emptyVNode: VNode, vNode: VNode) => any;

92

type InsertHook = (vNode: VNode) => any;

93

type PrePatchHook = (oldVNode: VNode, vNode: VNode) => any;

94

type UpdateHook = (oldVNode: VNode, vNode: VNode) => any;

95

type PostPatchHook = (oldVNode: VNode, vNode: VNode) => any;

96

type DestroyHook = (vNode: VNode) => any;

97

type RemoveHook = (vNode: VNode, removeCallback: () => void) => any;

98

type PostHook = () => any;

99

```

100

101

**Hook Usage Examples:**

102

103

```typescript

104

import { h, init, VNode } from "snabbdom";

105

106

// Element-level hooks

107

const elementWithHooks = h("div.animated", {

108

hook: {

109

init: (vnode: VNode) => {

110

console.log("Element initialized");

111

},

112

create: (emptyVnode: VNode, vnode: VNode) => {

113

console.log("DOM element created");

114

},

115

insert: (vnode: VNode) => {

116

// Safe to measure DOM here

117

const rect = (vnode.elm as Element).getBoundingClientRect();

118

console.log("Element inserted, size:", rect);

119

},

120

update: (oldVnode: VNode, vnode: VNode) => {

121

console.log("Element updated");

122

},

123

remove: (vnode: VNode, removeCallback: () => void) => {

124

// Animate out before removing

125

const elm = vnode.elm as HTMLElement;

126

elm.style.opacity = "0";

127

setTimeout(removeCallback, 300);

128

},

129

destroy: (vnode: VNode) => {

130

console.log("Element destroyed");

131

}

132

}

133

});

134

135

// Module-level hooks example

136

const animationModule = {

137

create: (emptyVnode: VNode, vnode: VNode) => {

138

const elm = vnode.elm as HTMLElement;

139

if (elm && vnode.data?.animate) {

140

elm.style.opacity = "0";

141

}

142

},

143

insert: (vnode: VNode) => {

144

const elm = vnode.elm as HTMLElement;

145

if (elm && vnode.data?.animate) {

146

setTimeout(() => {

147

elm.style.transition = "opacity 0.3s";

148

elm.style.opacity = "1";

149

}, 10);

150

}

151

}

152

};

153

154

const patch = init([animationModule]);

155

```

156

157

### AttachTo Helper

158

159

Utility for attaching virtual nodes to different DOM locations than their logical parent.

160

161

```typescript { .api }

162

/**

163

* Attach a virtual node to a different DOM location

164

* @param target - DOM element to attach to

165

* @param vnode - Virtual node to attach

166

* @returns Modified virtual node with attachment behavior

167

*/

168

function attachTo(target: Element, vnode: VNode): VNode;

169

170

interface AttachData {

171

[key: string]: any;

172

[i: number]: any;

173

placeholder?: any;

174

real?: Node;

175

}

176

```

177

178

**Usage Example:**

179

180

```typescript

181

import { attachTo, h, init } from "snabbdom";

182

183

const patch = init([]);

184

185

// Modal that renders in document.body but is managed in component tree

186

function Modal(props: { isOpen: boolean }): VNode {

187

if (!props.isOpen) {

188

return h("div"); // Empty placeholder

189

}

190

191

const modalContent = h("div.modal", [

192

h("div.modal-backdrop"),

193

h("div.modal-content", [

194

h("h2", "Modal Title"),

195

h("p", "Modal content goes here"),

196

h("button", "Close")

197

])

198

]);

199

200

// Attach modal to document.body instead of normal DOM position

201

return attachTo(document.body, modalContent);

202

}

203

204

// Usage in app

205

const app = h("div.app", [

206

h("h1", "Main App"),

207

h("button", "Open Modal"),

208

Modal({ isOpen: true }) // Renders in document.body

209

]);

210

```

211

212

### Utility Functions

213

214

Helper functions for type checking and manipulation.

215

216

```typescript { .api }

217

/**

218

* Check if value is an array (alias for Array.isArray)

219

*/

220

const array: (arg: any) => arg is any[];

221

222

/**

223

* Check if value is a primitive type (string or number)

224

*/

225

function primitive(s: any): s is string | number;

226

227

/**

228

* Default HTML DOM API implementation

229

*/

230

const htmlDomApi: DOMAPI;

231

```

232

233

**Usage Example:**

234

235

```typescript

236

import { array, primitive, htmlDomApi } from "snabbdom";

237

238

// Type checking utilities

239

const data = [1, 2, 3];

240

if (array(data)) {

241

console.log("Is array:", data.length);

242

}

243

244

const value = "hello";

245

if (primitive(value)) {

246

console.log("Is primitive:", value.toString());

247

}

248

249

// Custom DOM API (for testing or server environments)

250

const customDomApi = {

251

...htmlDomApi,

252

createElement: (tagName: string) => {

253

console.log("Creating element:", tagName);

254

return htmlDomApi.createElement(tagName);

255

}

256

};

257

258

const patch = init([], customDomApi);

259

```

260

261

## Advanced Patterns

262

263

### Component State Management

264

265

Using hooks to manage component-level state and effects.

266

267

```typescript

268

import { h, VNode, init } from "snabbdom";

269

270

interface ComponentState {

271

count: number;

272

mounted: boolean;

273

}

274

275

function Counter(initialCount: number = 0): VNode {

276

let state: ComponentState = { count: initialCount, mounted: false };

277

278

const increment = () => {

279

state.count++;

280

// Trigger re-render (you'd implement this in your app)

281

// render();

282

};

283

284

return h("div.counter", {

285

hook: {

286

insert: (vnode: VNode) => {

287

state.mounted = true;

288

console.log("Counter mounted with count:", state.count);

289

},

290

destroy: (vnode: VNode) => {

291

state.mounted = false;

292

console.log("Counter unmounted");

293

}

294

}

295

}, [

296

h("p", `Count: ${state.count}`),

297

h("button", {

298

on: { click: increment }

299

}, "Increment")

300

]);

301

}

302

```

303

304

### Performance Monitoring

305

306

Using hooks to monitor rendering performance.

307

308

```typescript

309

const performanceModule = {

310

pre: () => {

311

console.time("patch");

312

},

313

post: () => {

314

console.timeEnd("patch");

315

}

316

};

317

318

const patch = init([performanceModule]);

319

```

320

321

## Types

322

323

```typescript { .api }

324

interface ThunkData extends VNodeData {

325

fn: () => VNode;

326

args: any[];

327

}

328

329

interface Thunk extends VNode {

330

data: ThunkData;

331

}

332

333

interface ThunkFn {

334

(sel: string, fn: (...args: any[]) => any, args: any[]): Thunk;

335

(sel: string, key: any, fn: (...args: any[]) => any, args: any[]): Thunk;

336

}

337

```