| name | dom-walker |
| description | Fluent ES6 Proxy API for traversing and manipulating HTML DOM using dot notation. Built on TreeWalker. Use when you need to navigate the DOM by tag name, query elements, read/set attributes or properties, listen to events, or iterate over matched element sets — all without boilerplate.
|
| license | MIT |
| compatibility | Modern browsers with ES2022 support. Requires a live DOM (window/document). |
| metadata | {"package":"@actualwave/dom-walker","npm":"https://www.npmjs.com/package/@actualwave/dom-walker"} |
Overview
DOMWalker wraps a DOM element (or the document root) in an ES6 Proxy. Child
elements are accessed by lowercase tag name; calling a name as a function
invokes an augmentation (a named helper method). Results are always wrapped
proxies, so the API chains naturally.
Installation
npm install @actualwave/dom-walker
Setup
import { create } from '@actualwave/dom-walker';
const dom = create();
const dom = create(document.getElementById('app'));
const dom = create('#app');
const dom = create(document);
Traversal
Access children by lowercase tag name. Each step returns a new wrapped proxy.
When multiple siblings share the same tag, the result is a wrapped list.
const dom = create();
dom.html.body;
dom.html.body.header;
dom.html.body.ul.li;
dom.html.body.ul.li[0];
dom.html.body.ul.li[2];
Note: traversal of a multi-element list follows only the first node.
Use list augmentations (forEach, map, filter) to operate on all nodes,
or descendants() to collect matching elements across the whole subtree.
Augmentations
Node Augmentations
Available on any wrapped single node:
const section = dom.html.body.section;
section.name();
section.children();
section.children('div');
section.childAt(0);
section.descendants();
section.descendants('h2');
section.parent();
section.root();
List Augmentations
When the current proxy holds multiple nodes:
const items = dom.html.body.ul.li;
items.length();
items.at(1);
items.first();
items.forEach((item, i) => console.log(i));
items.map((item) => item.text());
items.filter((item) => item.attribute('hidden') === null);
items.reduce((acc, item) => acc + item.text(), '');
Element Augmentations
Read and mutate DOM element properties:
const el = dom.html.body.div;
el.name();
el.text();
el.attributes();
el.attribute('id');
el.attribute('id', 'main');
el.attribute('data-x', undefined);
el.query('p.highlight');
el.queryAll('p.highlight');
el.parent();
el.root();
Event Augmentations
const btn = dom.html.body.button;
const off = btn.on('click', (e) => console.log('clicked', e.target));
btn.off('click', handler);
btn.emit('click');
btn.emit(new MouseEvent('click', { bubbles: true }));
off();
$ Prefix — Element Property Access
Prefixing any property name with $ reads or writes the element's own
JavaScript property (not the HTML attribute):
const input = dom.html.body.form.input;
input.$value;
input.$checked;
input.$className;
input.$scrollTop;
input.$value('hello');
input.$checked(true);
Core Augmentations
el.toString();
el.valueOf();
Sub-Entry Imports
import BrowserDOMAdapter from '@actualwave/dom-walker/adapter';
import {
eventAugmentations,
elementAugmentations,
} from '@actualwave/dom-walker/augmentations';
Extending Augmentations
import { addAugmentations, resetAugmentations } from '@actualwave/dom-walker';
addAugmentations({
outerHTML: (node, adapter) => adapter.toNode(node)?.outerHTML ?? '',
hasClass: (node, adapter, [cls]) =>
adapter.toNode(node)?.classList.contains(cls) ?? false,
toggleClass: (node, adapter, [cls]) =>
adapter.toNode(node)?.classList.toggle(cls),
});
const dom = create();
dom.html.body.section.outerHTML();
dom.html.body.section.hasClass('active');
dom.html.body.section.toggleClass('open');
Custom Adapter
Pass a custom adapter to create() to override specific behaviours:
import { create } from '@actualwave/dom-walker';
import BrowserDOMAdapter from '@actualwave/dom-walker/adapter';
const myAdapter = {
...BrowserDOMAdapter,
getName: (node) => node.localName,
};
const dom = create(document.body, myAdapter);
UMD / Browser (no bundler)
<script src="dom-walker.umd.js"></script>
<script>
const { create } = DOMWalker;
const dom = create();
console.log(dom.html.body.valueOf().tagName);
dom.html.body.descendants('h2').forEach((h) => console.log(h.text()));
</script>
Global DOMWalker exposes: create, addAugmentations, resetAugmentations,
setNamePrefix, BrowserDOMAdapter, augmentations.eventAugmentations,
augmentations.elementAugmentations.
API Reference
create(root?, adapter?)
| Argument | Type | Default | Description |
|---|
root | Element | string | Document | document | Element, CSS selector string, or document |
adapter | Adapter | BrowserDOMAdapter | Adapter used for traversal |
Returns an opaque proxy. Do not rely on its type.
addAugmentations(map)
Registers additional augmentations accessible on all wrapped nodes.
resetAugmentations()
Removes all augmentations. Re-register any you need after calling this.
setNamePrefix(prefix, handlers)
Registers a one-character property prefix that activates a handler set.
The built-in $ prefix uses createHandlers() from
@actualwave/tree-walker/property-handlers to provide element property access.
Common Patterns
Collect text from all matching elements
const headings = create().html.body.descendants('h2');
const texts = headings.map((h) => h.text());
Check element presence before acting
const modal = create('#modal');
if ('button' in modal) {
modal.button.on('click', close);
}
Batch-remove a class
create('.card').filter((card) => card.hasClass('selected'))
.forEach((card) => card.toggleClass('selected'));
Event delegation with unsubscribe
const cleanup = create('#list').on('click', (e) => {
if (e.target.matches('li')) handleClick(e.target);
});
cleanup();