@abradley2/dommy

Tiny-to-the-point-of-almost-being-a-joke virtual DOM utility

Usage no npm install needed!

<script type="module">
  import abradley2Dommy from 'https://cdn.skypack.dev/@abradley2/dommy';
</script>

README

DOMMY

Custom Element rendering for dummies.

Installation npm install --save @abradley2/dommy

Motivation

I wanted a convenience function for rendering in custom elements, without importing a library like Polymer that completely redefines how I create custom elements. I just want to render stuff without losing functionality, and with the same "diff/patch" virtual DOM efficiency libraries like React gives me.

This library uses morphdom under the hood as the diffing engine, similar to yo-yo. But unlike yo-yo, uses a createElement function instead of ES6 template tags in favor of supporting JSX.

API

DOMMY has two functions. Only one of which you will use directly.

createElement
This is just for using JSX. With babel-plugin-transform-react-jsx or any other source transform that lets you use a custom jsx pragma, simply do:

/** @jsx createElement */
import { createElement } from '@abradley2/dommy'

Kewl. Now you can use JSX with DOMMY just as you would with React.

render
This is the only function of DOMMY you'll actually use.

/** @jsx createElement */
import { createElement, render } from '@abradley2/dommy'

var count = 0

const update = () => 
  render(
    this,
    <div>
      <button
        onclick={() => {
          count += 1
          update()
        }}
      >
        {`Clicked ${count} times`}
      </button>
    </div>
  )

update() // initial render

Guide: Usage With Custom Elements

This is the main motivation behind DOMMY and if it's not what you're using it for there's 100% definitely a better solution for you out there.

Let's start with a simple counter element like in the original example. Hardly anything changes here.

class MyCounter extends HTMLElement {
  connectedCallback () {
    var count = 0

    this.update = () => {
      render(
        this,
        <div>
          <button
            onclick={() => {
              count += 1
              this.update()
            }}
          >
            {`Clicked ${count} times`}
          </button>
        </div>
      )
    }

    this.update()
  }
}

Ok. Kewl. Now let's allow the application to pass in an attribute called "buttontitle" to our custom element and use it in the render function. Really, we're just doing what we normally do with custom elements: using this.getAttribute to handle data passed in from the parent.

this.update = () => {
  render(
    this,
    <div>
      <h3>{this.getAttribute("buttontitle")}</h3>
      <button
        onclick={() => {
          count += 1
          this.update()
        }}
      >
        {`Clicked ${count} times`}
      </button>
    </div>
  )
}

Awesome. But buttontitle might not always be the same as it was when the component was mounted. Once again, the solution is just doing what we normally do with web components.

class MyCounter extends HTMLElement {
  static get observedAttributes () {
    return ['buttontitle']
  }

  attributeChangedCallback() {
    if (this.update) this.update()
  }