Fork me on GitHub

somedom

Building blocks for the DOM.

Installation

Get it through npm or yarn, e.g.

$ npm install somedom --save-dev

Now you can import the bits you need, see below.

E2E Tests

This guide has embbeded <script> tags invoking test(...) calls, no wonder yet.

Behind there's a function named appendChild linked to document.currentScript at execution time.

Example

Those appendChild calls are removed from the code for readability.

output:

Also, somedom is bound to this function.

output:

Errors thrown are captured and shown as below:

output:

Reference API

Produce, patch and render vnodes, mount/unmount them from the DOM, mix and compose hooks, etc.

h()
h(name[, props], ...children)

This function will produce a vnode value.

output:
pre()
pre(vnode[, svg[, cb]])

Use this function to debug vnodes and tag functions.

output:
bind()
bind(render[, ...extensions])

This function will help you to merge given middleware as a tag function.

It receives an initial render function and a list of extensions to be applied:

  • Any factory function will be used as render callback, e.g. attributes(...), listeners(...), etc.
  • If you pass either an object or an array of objects, those will be registered as custom tags on the bound function.
output:

Always return a valid HTMLElement or TextNode, otherwise return cb(..., svg).

output:
mount()
mount(target[, vnode[, cb]])

Use this function to attach elements on the DOM, it receives an string selector or HTMLElement as target, the given vnode will be the source.

If no target is given it will use document.body as fallback.

Passing a custom tag (cb) function also works.

output:

Rendering from multiple nodes is possible through DocumentFragment, e.g.

output:
patch()
patch(target, vnode, next[, svg[, cb]])

Update a previous vnode with a next one, this function will fix the DOM for you.

It will also sync hooks from any given tag function.

render()
render(vnode[, svg[, cb]])

This function accepts only scalars and vnode values.

output:

Given strings are rendered as TextNode elements.

output:

You can render single or nested vnodes, attributes are supported as well.

output:

SVG support is handled for you. However, elements without an svg root requires true as second argument.

output:

All functions are executed during render calls.

output:
unmount()
unmount(target[, cb])

Removes the given node from the DOM. It also invoke registered hooks before complete removal.

If you give a function as second argument, the element is removed only when done is called.

    Available Hooks

    Listen for events on the DOM, setup element's lifecycle or enhance dynamic class names, etc.

    listeners()
    listeners([globals])

    This hook allows you to bind any event-handler from your elements' props.

    Any given globals will be also used as default event handlers, if they return false the rest of handlers will be skipped.

    output:

    Event listeners also help you to manage the element's lifecycle: oncreate, onupdate and ondestroy.

    output:
    attributes()
    attributes([helpers])

    Through this hook style and class props can be fixed if they're objects.

    output:

    Also update, enter and exit props can be used for toggling classes during the elements' lifecycle.

    output:

      Otherwise, any given props matching helpers will be invoked as fallback for unhandled props.

      output:

      Non matched props that remain as objects will be converted to data-* attributes.

      output:

      Server Side Rendering

      To render entire vnode trees on the back-end use:

      import {
        enable,
        disable,
        findOne,
        findAll,
        useWindow,
        parseMarkup,
        markupAdapter,
        renderToString,
        bindHelpers as $,
      } from 'somedom/ssr';
      enable()
      enable([env])

      The `env` argument is used to retrieve the `jsdom` or `happy-dom` modules from the user, e.g.

      // CommonJS
      const happydom = require('happy-dom');
      const jsdom = require('jsdom');
      
      enable({ jsdom, happydom });
      
      // ESM
      import * as happydom from 'happy-dom';
      import * as jsdom from 'jsdom';
      
      enable({ jsdom, happydom });
      

      You can set those conditionally: `happy-dom` will be tried first, then `jsdom`, otherwise the built-in environment will be used.

      disable()
      disable()

      This will clear the globals set by the method above, use after your tests or SSR stuff.

      useWindow()
      useWindow(cb)

      Use this hook to patch document and window globally during the callback's lifecycle.

      useWindow(() => {
        var span = document.createElement('span');
        var text = document.createTextNode('OSOM');
      
        span.appendChild(text);
      
        console.log(span.outerHTML);
        // <span>OSOM</span>
      });
      bindHelpers()
      bindHelpers(node)

      Use this to wrap an existing node, e.g. document.body — it'll return the given node with findText() and withText() methods attached.

      var $ = bindHelpers;
      
      // lets say you have an application
      var el = document.createElement('div');
      var app = new Application(el, {
        value: 'Hello.',
      });
      
      // wrap to enable lookup methods
      var $root = $(app.target);
      
      // returns the first node matching
      $root.withText('Click me.').dispatchEvent(new Event('click'));

      The method above returns a single instance from calling findText() which just returns a list for matching nodes.

      var button = $root.findText(/Click me/)[0];
      
      button.dispatchEvent(new Event('click'));
      findOne()
      findOne(css, nodes[, adapter])

      Returns a node matching the css-selector, used by SSR's `querySelector` implementation.

      findAll()
      findAll(css, nodes[, adapter])

      Returns all nodes matching the css-selector, used by SSR's `querySelectorAll` implementation.

      markupAdapter
      { isTag, getAttributeValue, getName, getChildren, getParent, getText, removeSubsets, existsOne, getSiblings, hasAttrib, findOne, findAll }

      Implements the required methods for `css-select` adapters, used by methods above. You can extend from here to make your own adapter.

      parseMarkup()
      parseMarkup(html[, options])

      Returns an AST from parsed HTML, used by SSR's `innerHTML` implementation.

      var test = '<b>OSOM</b>';
      var ast = parseMarkup(test);
      
      console.log(ast);
      // [ { type: 'element', rawTagName: 'b', tagName: 'b', attributes: [], children: [ [Object] ] } ]
      renderToString()
      renderToString(vnode[, cb])

      Returns a new function, when invoked it'll produce HTML as its output.

      var test = ['h1', ['It works!']];
      var dom = renderToString(test);
      var html = await dom();
      
      console.log(html);
      // <h1>It works!</h1>

      Any given callback will be used as tag function.

      var $ = bind(render, attributes({
        class: classes,
      }));
      
      var dom = renderToString(vnode, $);
      var html = await dom();