0
# Advanced VNode Functions
1
2
Lower-level VNode creation and manipulation functions for advanced use cases, providing direct access to Inferno's virtual DOM internals while maintaining React compatibility.
3
4
## Capabilities
5
6
### createVNode Function
7
8
Creates virtual DOM nodes with explicit flags and properties for maximum control.
9
10
```typescript { .api }
11
/**
12
* Creates a virtual DOM node with explicit configuration
13
* @param flags - VNode flags defining element type and behavior
14
* @param type - Element type (string for DOM, function/class for components)
15
* @param className - CSS class name for the element
16
* @param children - Child nodes
17
* @param childFlags - Flags describing children structure
18
* @param props - Element properties and attributes
19
* @param key - Unique key for reconciliation
20
* @param ref - Reference to DOM element or component instance
21
* @returns VNode representing the virtual DOM element
22
*/
23
function createVNode(
24
flags: number,
25
type: string | ComponentClass<any> | Function | null,
26
className?: string,
27
children?: InfernoNode,
28
childFlags?: number,
29
props?: any,
30
key?: string | number,
31
ref?: any
32
): VNode;
33
```
34
35
**Usage Examples:**
36
37
```typescript
38
import { createVNode, VNodeFlags } from "inferno-compat";
39
40
// Create a simple element VNode
41
const div = createVNode(
42
VNodeFlags.HtmlElement,
43
'div',
44
'container',
45
'Hello World',
46
VNodeFlags.HasNonKeyedChildren,
47
{ id: 'main' },
48
'unique-key'
49
);
50
51
// Create a component VNode
52
function MyComponent(props) {
53
return createVNode(VNodeFlags.HtmlElement, 'span', null, props.text);
54
}
55
56
const component = createVNode(
57
VNodeFlags.ComponentFunction,
58
MyComponent,
59
null,
60
null,
61
VNodeFlags.HasNonKeyedChildren,
62
{ text: 'Component text' },
63
'component-key'
64
);
65
66
// Create VNode with ref
67
let elementRef;
68
const withRef = createVNode(
69
VNodeFlags.HtmlElement,
70
'input',
71
'form-input',
72
null,
73
VNodeFlags.HasNonKeyedChildren,
74
{ type: 'text', placeholder: 'Enter text' },
75
null,
76
(ref) => { elementRef = ref; }
77
);
78
```
79
80
### createComponentVNode Function
81
82
Creates VNodes specifically for React/Inferno components.
83
84
```typescript { .api }
85
/**
86
* Creates a VNode for a component (class or function)
87
* @param flags - Component flags (ComponentClass or ComponentFunction)
88
* @param type - Component class or function
89
* @param props - Component props
90
* @param key - Unique key for reconciliation
91
* @param ref - Reference to component instance
92
* @returns VNode for the component
93
*/
94
function createComponentVNode(
95
flags: number,
96
type: ComponentClass<any> | Function,
97
props?: any,
98
key?: string | number,
99
ref?: any
100
): VNode;
101
```
102
103
**Usage Examples:**
104
105
```typescript
106
import { createComponentVNode, VNodeFlags, Component } from "inferno-compat";
107
108
class UserProfile extends Component {
109
render() {
110
return <div>User: {this.props.name}</div>;
111
}
112
}
113
114
// Create class component VNode
115
const classComponent = createComponentVNode(
116
VNodeFlags.ComponentClass,
117
UserProfile,
118
{ name: 'Alice', age: 30 },
119
'user-profile',
120
(instance) => console.log('Component mounted:', instance)
121
);
122
123
// Function component VNode
124
function WelcomeMessage({ message }) {
125
return <h1>{message}</h1>;
126
}
127
128
const functionComponent = createComponentVNode(
129
VNodeFlags.ComponentFunction,
130
WelcomeMessage,
131
{ message: 'Welcome to our app!' },
132
'welcome-message'
133
);
134
135
// Higher-order component pattern
136
function withLogging(WrappedComponent) {
137
function LoggingComponent(props) {
138
console.log('Rendering with props:', props);
139
return createComponentVNode(
140
VNodeFlags.ComponentFunction,
141
WrappedComponent,
142
props
143
);
144
}
145
return LoggingComponent;
146
}
147
148
const EnhancedComponent = withLogging(WelcomeMessage);
149
const enhanced = createComponentVNode(
150
VNodeFlags.ComponentFunction,
151
EnhancedComponent,
152
{ message: 'Enhanced message' }
153
);
154
```
155
156
### createTextVNode Function
157
158
Creates text nodes for efficient text rendering.
159
160
```typescript { .api }
161
/**
162
* Creates a text VNode for rendering text content
163
* @param text - Text content to render
164
* @param key - Optional key for reconciliation
165
* @returns VNode representing text content
166
*/
167
function createTextVNode(text: string | number, key?: string | number): VNode;
168
```
169
170
**Usage Examples:**
171
172
```typescript
173
import { createTextVNode, createVNode, VNodeFlags } from "inferno-compat";
174
175
// Simple text node
176
const greeting = createTextVNode('Hello World!');
177
178
// Text with key for lists
179
const listItems = ['Apple', 'Banana', 'Cherry'].map((fruit, index) =>
180
createVNode(
181
VNodeFlags.HtmlElement,
182
'li',
183
null,
184
createTextVNode(fruit, `fruit-${index}`),
185
VNodeFlags.HasNonKeyedChildren,
186
null,
187
`item-${index}`
188
)
189
);
190
191
// Dynamic text content
192
function DynamicText({ value, formatter }) {
193
const formattedValue = formatter ? formatter(value) : value;
194
return createTextVNode(formattedValue);
195
}
196
197
// Conditional text rendering
198
function StatusText({ status }) {
199
const text = status === 'loading'
200
? createTextVNode('Loading...', 'loading-text')
201
: createTextVNode(`Status: ${status}`, 'status-text');
202
203
return createVNode(
204
VNodeFlags.HtmlElement,
205
'span',
206
`status ${status}`,
207
text
208
);
209
}
210
211
// Number text nodes
212
const counter = createTextVNode(42);
213
const price = createTextVNode(19.99);
214
```
215
216
### createFragment Function
217
218
Creates fragment nodes for grouping elements without DOM wrappers.
219
220
```typescript { .api }
221
/**
222
* Creates a fragment VNode for grouping multiple elements
223
* @param children - Array of child VNodes
224
* @param childFlags - Flags describing children structure
225
* @param key - Optional key for reconciliation
226
* @returns Fragment VNode containing the children
227
*/
228
function createFragment(
229
children: InfernoNode[],
230
childFlags?: number,
231
key?: string | number
232
): VNode;
233
```
234
235
**Usage Examples:**
236
237
```typescript
238
import { createFragment, createVNode, createTextVNode, VNodeFlags } from "inferno-compat";
239
240
// Simple fragment
241
const fragment = createFragment([
242
createVNode(VNodeFlags.HtmlElement, 'h1', null, createTextVNode('Title')),
243
createVNode(VNodeFlags.HtmlElement, 'p', null, createTextVNode('Content'))
244
], VNodeFlags.HasNonKeyedChildren);
245
246
// Fragment in conditional rendering
247
function ConditionalContent({ showDetails, title, content }) {
248
if (!showDetails) {
249
return createTextVNode(title);
250
}
251
252
return createFragment([
253
createVNode(VNodeFlags.HtmlElement, 'h2', null, createTextVNode(title)),
254
createVNode(VNodeFlags.HtmlElement, 'p', null, createTextVNode(content)),
255
createVNode(VNodeFlags.HtmlElement, 'button', null, createTextVNode('Close'))
256
], VNodeFlags.HasNonKeyedChildren, 'details-fragment');
257
}
258
259
// Fragment for list items
260
function TableRow({ cells }) {
261
const cellVNodes = cells.map((cell, index) =>
262
createVNode(
263
VNodeFlags.HtmlElement,
264
'td',
265
null,
266
createTextVNode(cell),
267
VNodeFlags.HasNonKeyedChildren,
268
null,
269
`cell-${index}`
270
)
271
);
272
273
return createFragment(cellVNodes, VNodeFlags.HasKeyedChildren, 'table-row');
274
}
275
276
// Nested fragments
277
const nestedFragment = createFragment([
278
createTextVNode('Before nested'),
279
createFragment([
280
createVNode(VNodeFlags.HtmlElement, 'span', null, createTextVNode('Nested 1')),
281
createVNode(VNodeFlags.HtmlElement, 'span', null, createTextVNode('Nested 2'))
282
], VNodeFlags.HasNonKeyedChildren, 'inner-fragment'),
283
createTextVNode('After nested')
284
], VNodeFlags.HasNonKeyedChildren, 'outer-fragment');
285
```
286
287
### createPortal Function
288
289
Creates portal nodes that render children into different DOM containers.
290
291
```typescript { .api }
292
/**
293
* Creates a portal VNode that renders children into a different DOM container
294
* @param children - VNodes to render in the portal
295
* @param container - DOM element to render the portal into
296
* @returns Portal VNode that renders children elsewhere
297
*/
298
function createPortal(
299
children: InfernoNode,
300
container: Element
301
): VNode;
302
```
303
304
**Usage Examples:**
305
306
```typescript
307
import { createPortal, createVNode, createTextVNode, VNodeFlags, Component } from "inferno-compat";
308
309
// Modal component using portal
310
class Modal extends Component {
311
constructor(props) {
312
super(props);
313
this.modalRoot = document.getElementById('modal-root') || document.body;
314
}
315
316
render() {
317
const modal = createVNode(
318
VNodeFlags.HtmlElement,
319
'div',
320
'modal-backdrop',
321
createVNode(
322
VNodeFlags.HtmlElement,
323
'div',
324
'modal-content',
325
this.props.children
326
)
327
);
328
329
return createPortal(modal, this.modalRoot);
330
}
331
}
332
333
// Tooltip component
334
function Tooltip({ children, content, targetRef }) {
335
if (!targetRef.current) return null;
336
337
const tooltip = createVNode(
338
VNodeFlags.HtmlElement,
339
'div',
340
'tooltip',
341
createTextVNode(content)
342
);
343
344
return createPortal(tooltip, targetRef.current.parentElement);
345
}
346
347
// Notification system
348
class NotificationManager extends Component {
349
constructor(props) {
350
super(props);
351
this.state = { notifications: [] };
352
this.notificationContainer = document.getElementById('notifications');
353
}
354
355
addNotification = (message, type = 'info') => {
356
const notification = {
357
id: Date.now(),
358
message,
359
type
360
};
361
362
this.setState(prevState => ({
363
notifications: [...prevState.notifications, notification]
364
}));
365
}
366
367
render() {
368
const { notifications } = this.state;
369
370
if (notifications.length === 0) return null;
371
372
const notificationList = createVNode(
373
VNodeFlags.HtmlElement,
374
'div',
375
'notification-list',
376
notifications.map(notification =>
377
createVNode(
378
VNodeFlags.HtmlElement,
379
'div',
380
`notification ${notification.type}`,
381
createTextVNode(notification.message),
382
VNodeFlags.HasNonKeyedChildren,
383
null,
384
notification.id
385
)
386
)
387
);
388
389
return createPortal(notificationList, this.notificationContainer);
390
}
391
}
392
```
393
394
### createRef Function
395
396
Creates ref objects for accessing DOM elements and component instances.
397
398
```typescript { .api }
399
/**
400
* Creates a ref object for accessing DOM elements or component instances
401
* @returns Ref object with current property
402
*/
403
function createRef<T = any>(): { current: T | null };
404
```
405
406
**Usage Examples:**
407
408
```typescript
409
import { createRef, createVNode, VNodeFlags, Component } from "inferno-compat";
410
411
class InputComponent extends Component {
412
constructor(props) {
413
super(props);
414
this.inputRef = createRef();
415
}
416
417
componentDidMount() {
418
// Focus the input after mounting
419
if (this.inputRef.current) {
420
this.inputRef.current.focus();
421
}
422
}
423
424
getValue = () => {
425
return this.inputRef.current ? this.inputRef.current.value : '';
426
}
427
428
render() {
429
return createVNode(
430
VNodeFlags.HtmlElement,
431
'input',
432
'form-input',
433
null,
434
VNodeFlags.HasNonKeyedChildren,
435
{
436
type: 'text',
437
placeholder: this.props.placeholder,
438
ref: this.inputRef
439
}
440
);
441
}
442
}
443
444
// Functional component with ref
445
function VideoPlayer({ src }) {
446
const videoRef = createRef();
447
448
const play = () => {
449
if (videoRef.current) {
450
videoRef.current.play();
451
}
452
};
453
454
const pause = () => {
455
if (videoRef.current) {
456
videoRef.current.pause();
457
}
458
};
459
460
return createFragment([
461
createVNode(
462
VNodeFlags.HtmlElement,
463
'video',
464
'video-player',
465
null,
466
VNodeFlags.HasNonKeyedChildren,
467
{ src, ref: videoRef }
468
),
469
createVNode(
470
VNodeFlags.HtmlElement,
471
'div',
472
'controls',
473
[
474
createVNode(
475
VNodeFlags.HtmlElement,
476
'button',
477
null,
478
createTextVNode('Play'),
479
VNodeFlags.HasNonKeyedChildren,
480
{ onClick: play }
481
),
482
createVNode(
483
VNodeFlags.HtmlElement,
484
'button',
485
null,
486
createTextVNode('Pause'),
487
VNodeFlags.HasNonKeyedChildren,
488
{ onClick: pause }
489
)
490
]
491
)
492
]);
493
}
494
```
495
496
### forwardRef Function
497
498
Creates components that forward refs to child elements.
499
500
```typescript { .api }
501
/**
502
* Creates a component that forwards refs to child elements
503
* @param render - Render function that receives props and ref
504
* @returns Component that forwards refs
505
*/
506
function forwardRef<T, P = {}>(
507
render: (props: P, ref: { current: T | null }) => InfernoNode
508
): ComponentType<P & { ref?: { current: T | null } }>;
509
```
510
511
**Usage Examples:**
512
513
```typescript
514
import { forwardRef, createVNode, VNodeFlags, createRef } from "inferno-compat";
515
516
// Forward ref to DOM element
517
const FancyButton = forwardRef((props, ref) => {
518
return createVNode(
519
VNodeFlags.HtmlElement,
520
'button',
521
`fancy-button ${props.variant || 'primary'}`,
522
createTextVNode(props.children),
523
VNodeFlags.HasNonKeyedChildren,
524
{
525
...props,
526
ref: ref
527
}
528
);
529
});
530
531
// Usage with ref
532
function App() {
533
const buttonRef = createRef();
534
535
const handleClick = () => {
536
if (buttonRef.current) {
537
buttonRef.current.classList.add('clicked');
538
}
539
};
540
541
return createVNode(
542
VNodeFlags.ComponentFunction,
543
FancyButton,
544
null,
545
null,
546
VNodeFlags.HasNonKeyedChildren,
547
{
548
variant: 'secondary',
549
onClick: handleClick,
550
ref: buttonRef,
551
children: 'Click Me'
552
}
553
);
554
}
555
556
// Forward ref to child component
557
const EnhancedInput = forwardRef((props, ref) => {
558
return createVNode(
559
VNodeFlags.HtmlElement,
560
'div',
561
'input-wrapper',
562
[
563
props.label && createVNode(
564
VNodeFlags.HtmlElement,
565
'label',
566
'input-label',
567
createTextVNode(props.label)
568
),
569
createVNode(
570
VNodeFlags.HtmlElement,
571
'input',
572
'enhanced-input',
573
null,
574
VNodeFlags.HasNonKeyedChildren,
575
{
576
...props,
577
ref: ref
578
}
579
)
580
]
581
);
582
});
583
```
584
585
### VNode Flags
586
587
Understanding VNode flags is crucial for advanced VNode manipulation:
588
589
```typescript { .api }
590
enum VNodeFlags {
591
// Element types
592
HtmlElement = 1,
593
SvgElement = 2,
594
InputElement = 4,
595
TextareaElement = 8,
596
SelectElement = 16,
597
598
// Component types
599
ComponentFunction = 32,
600
ComponentClass = 64,
601
ComponentUnknown = 128,
602
603
// Children types
604
HasKeyedChildren = 256,
605
HasNonKeyedChildren = 512,
606
607
// Special flags
608
Fragment = 1024,
609
Portal = 2048,
610
ReCreate = 4096,
611
ContentEditable = 8192,
612
UpdateEffect = 16384,
613
Ref = 32768
614
}
615
```
616
617
### Advanced Patterns
618
619
These functions enable advanced patterns like:
620
621
- **Custom renderers**: Building alternative rendering targets
622
- **Performance optimization**: Fine-grained control over reconciliation
623
- **Framework integration**: Bridging with other UI libraries
624
- **Testing utilities**: Creating controlled virtual DOM structures
625
- **Development tools**: Building debugging and inspection tools