Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Dom Laravel Package

windwalker/dom

Windwalker Dom is a PHP package for parsing, querying, and manipulating HTML and XML documents with an intuitive API. It offers node traversal, CSS-style selectors, and safe document building, making it handy for scraping, templating, and content transformation in Laravel or any Composer-based proje...

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install via Composer (the package targets Windwalker 4, so PHP 8.1+ recommended):

    composer require windwalker/dom ^4.0
    
  2. Look here first, in order:

    • The official docs: https://windwalker.io/documentation/components/dom/ — it is the only real prose documentation; the GitHub README only links to it.
    • src/ — especially HtmlElement, DomElement, HtmlElements, and src/Builder/HtmlBuilder.php. These are the classes you will actually touch.
    • tests/ — the test suite is effectively the API reference for edge cases (void tags, boolean attributes, escaping).
    • Then the Windwalker framework repo if you need broader context, since bug reports live there (windwalker-io/framework).
  3. Minimal first example — build a fragment without string concatenation:

    use Windwalker\DOM\Builder\HtmlBuilder;
    
    $html = HtmlBuilder::create('div', ['class' => 'alert alert-danger'], 'Something went wrong');
    
    echo $html; // <div class="alert alert-danger">Something went wrong</div>
    

    Or with the object API:

    use Windwalker\DOM\HtmlElement;
    
    $el = new HtmlElement('a', ['href' => '/users/1'], 'Profile');
    echo $el->toString(); // or (string) $el
    
  4. First real use case: replacing hand-built HTML strings in a controller, mail builder, or CLI report generator where you need to assemble nested markup from data. Start with a small helper that returns an HtmlElement and echo/concatenate it inside your existing templates.

Verify exact class names against src/ for your installed version — Windwalker has bumped namespaces and class locations across major versions.

Implementation Patterns

Fragment helpers instead of inline concatenation. Wrap repeated markup in small factory functions that return HtmlElement objects. This keeps templates readable and centralizes attribute handling:

function alert(string $type, string $message): HtmlElement
{
    return new HtmlElement('div', ['class' => "alert alert-$type", 'role' => 'alert'], $message);
}

echo alert('danger', $exception->getMessage());

Compose nested trees, render once. Use appendChild()/child content to build depth, then render at the boundary (controller output, mail body). This is the "virtual DOM" payoff: structure is data, string is a final step.

$list = new HtmlElement('ul', ['class' => 'items']);

foreach ($items as $item) {
    $list->appendChild(new HtmlElement('li', ['data-id' => $item->id], $item->name));
}

echo $list; // <ul class="items"><li data-id="1">…</li>…</ul>

Builder primitives for common widgets. The HtmlBuilder class historically exposes helpers like attributes(), input(), option(), options(), checkbox(), textarea(). Reach for these instead of rebuilding attribute serialization by hand — this is where escaping and boolean-attribute rules are already correct.

Collections for tables/lists. HtmlElements (an array-like container) is useful when you want to pass a group of elements around before rendering, or map/reduce over children.

Integration strategy.

  • In a Laravel controller/Blade pipeline: use it to generate fragments, then pass the rendered string into a {!! !!} slot (only for trusted content — see Gotchas).
  • In mail builders or PDF generators: this is where string-DOM is most natural since you often cannot use a full Blade view.
  • In CLI/code-generation tooling: it is a clean way to emit XML/HTML without templating overhead.
  • Wrap it: define your own thin Html service/interface around the builder and bind it in the container. With only 9 stars and 0 dependents, you want one seam to swap the library later.

Testing. Assert against rendered strings with assertSame(); the normalized attribute ordering (see below) makes output deterministic, which makes snapshot-style tests viable.

Config. There is essentially no config file — behavior is controlled per-call (XHTML flag on create(), attribute arrays, content-type escaping). Treat constructor/builder arguments as your configuration surface and centralize them in helpers.

Gotchas and Tips

  • Thin documentation is the biggest pitfall. The README is essentially a badge page. Budget time to read the test suite; that is where the intended API is demonstrated. Do not assume Laravel's Illuminate\View-style behavior.
  • Namespace/version drift. Windwalker has shifted from Windwalker\DOM to Windwalker\Dom (and class renames like DomElement/HtmlElement) between majors. Pin ^4.0, check composer.lock, and read the installed src/ rather than copying snippets from older blog posts.
  • Escaping is not automatic everywhere. Attribute values are escaped; content passed as a string is typically treated as text and escaped — but if you inject pre-rendered HtmlElement/raw strings, they are not re-escaped. Never pass user input into a "raw" content path. Decide per helper whether content is trusted.
  • Double-escaping. If you pre-escape manually and then hand the string to the builder, you get &amp;amp;. Let the element handle text content; only escape at the boundary.
  • Void/self-closing elements. input, img, br, hr, meta, link require the void-element path (HtmlBuilder::input() or the builder's void handling). Writing <input></input> by hand or via a generic create() can produce invalid HTML. Use the dedicated helpers or pass the XHTML flag consciously.
  • Boolean attributes. Passing ['disabled' => true] may render as disabled="disabled" or disabled="1" depending on the API path; use the HtmlBuilder::boolean()/attribute helper rather than raw arrays if exact output matters.
  • Attribute ordering and normalization. Output ordering follows the internal attribute map, not your input order in all cases. Don't write tests that assume arbitrary ordering; assert on the actual rendered string once and keep it stable.
  • Low adoption risk. 9 stars, 0 dependents, "read only" mirror. It is a component of a larger framework, not a standalone community project. Isolate it behind an interface, and avoid relying on undocumented internals (protected methods on DomElement) in case the mirror stops syncing.
  • Debugging tip. The fastest way to debug a malformed tree is var_dump((string) $el) at each level, or json_encode a simplified tree, rather than stepping through builder internals. When output differs from expectation, check whether the child was appended as a string vs an element first.
  • When not to use it. It is for dynamic fragments. Do not build whole pages or email layouts this way — use Blade/Twig for outer structure and reserve Windwalker DOM for the data-driven inner chunks.
  • Extension points. Subclass HtmlElement or add your own static builder helpers for domain-specific tags; that keeps call sites short and gives you one place to change if you migrate off the package.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment