Domovoy API

Working with Elements

Two-Step Factory Pattern

Element functions use a curried two-step pattern powered by FutureNode :

  1. First call — pass attributes (named arguments with IDE autocompletion):

    use function Domovoy\VirtualDom\Generated\div;
    
    $future = div(id: 'main', className: 'container');
    // Returns a FutureNode<DivNode>
  2. Second call — pass children to produce the final node:

    $node = $future('Hello', $childNode, 42);
    // Returns a DivNode

Typically written as a single chained expression:

$node = div(id: 'main', className: 'container')(
    p()('First paragraph'),
    p()('Second paragraph'),
);

Typed Attributes

Each element has a generated attributes class with typed properties matching the W3C IDL specification. Your IDE provides autocompletion for every attribute:

use function Domovoy\VirtualDom\Generated\input;

// PHPStan checks that 'type' is ?string, 'disabled' is ?bool, etc.
$node = input(type: 'email', required: true, placeholder: 'you@example.com');

IDL property names are mapped to HTML attribute names automatically (className becomes class , htmlFor becomes for ).

Void Elements

Void elements (br , img , input , hr , meta , link , ...) return a Node directly — no second call needed:

use function Domovoy\VirtualDom\Generated\{img, br, hr};

$image = img(src: '/logo.png', alt: 'Logo');
$break = br();
$rule = hr();

Children Auto-Wrapping

String and numeric values among children are automatically wrapped in TextNode with HTML escaping:

$node = p()('Price: ', 42, ' EUR');
// <p>Price: 42 EUR</p>

null children are silently ignored, which is useful for conditional rendering:

$node = div()(
    $showHeader ? h1()('Title') : null,
    p()('Content'),
);

Closures are invoked and their return values used as child nodes:

$node = div()(
    fn () => p()('Lazy child'),
);

Raw HTML

To insert unescaped HTML, use the raw() helper:

use function Domovoy\VirtualDom\raw;

$node = div()(raw('<strong>Bold text</strong>'));

The caller is responsible for ensuring the HTML is safe. This is intentional — Domovoy escapes everything else by default.

DOCTYPE Declaration

use function Domovoy\VirtualDom\doctype;

$dtd = doctype();       // <!DOCTYPE html>
$dtd = doctype('xml');  // <!DOCTYPE xml>

Fragments

Group multiple nodes without producing an HTML tag:

use function Domovoy\VirtualDom\fragment;

$group = fragment(
    p()('First'),
    p()('Second'),
);
// Renders as: <p>First</p><p>Second</p>

Fragments are useful for returning multiple nodes from a template or function.

Search results