Control DOM mutations with DNA 3

After 2 years of development and almost 1 year of refinement, we are pleased to announce DNA 3, the new version of the UI library we built upon the Web Components specifications.

What's DNA?

DNA is a component library developed by Chialab for their Web projects. In 2015, the mission of DNA was to bring modern JavaScript features like ES6 imports and classes to the first Web Components specification that were based on HTML Imports and plain Function constructors. When those features became part of the Custom Elements v1 specification, we released the 2nd version of the library with the intent to provide a compatibility layer that would not require any polyfill. Today, the most of the browsers have base support for Custom Elements (unfortunately, many of them do not support customised built-in elements) and Shadow DOM, but we still require a performant template engine as well as compatibility with some legacy browsers like IE 11 and old Safari versions.

Versions of DNA

Gotchas

Because of the lack of native support, when we developed DNA 2 in 2017 we had to make a lot of abstractions. In the end, DNA's components looked like Custom Elements, but they were not. It means that inspecting the node in the DOM was not the same of inspecting the component instance. This aspect reduced the developer experience and the interoperability with the ecosystem.

Developing DNA 3

By switching the main target of the library to modern browsers, the new aim for DNA 3 is to increase the Developer Experience without sacrificing performance and to still provide a compatibility layer for the legacy browsers. Supporting real inspectable Custom Elements means out of the box support for devtools, third party libraries and documentation tools like Storybook. We also followed the Documentation Driven Development pattern in first place, in order to design better tests for the TDD phase.

WebComponents that almost work everywhere

The tagline Progressive Web Components refers to the ability of the library to progressively insert compatibility layers when required. In the latest version of Chrome, it simple uses the native Custom Element Registry, in Safari it adds support for customised built-in elements, in IE 11 it uses a custom registry and updates node's prototype. This is made possibile thanks to the abstraction of the core DOM methods like appendChild and removeChild during the rendering in order to correctly trigger life cycle hooks.

Instead of using a MutationObserver, DNA uses its template engine to connect nodes as well as render slotted children. You don't need to require any specific polyfill for Web Components with the result of a deterministic rendering phase tested against a large number of legacy browsers.

Test DNA

Node and SSR environments

Thanks to the abstraction of the DOM methods, DNA can render outside of the browser, for example in Node environments. It can be useful for SSR purposes or for some applications that have to manage an HTML file. DNA can also be used to generate pages in serverless environments like Firebase or AWS Api Gateway with full functionalities support as for the hydrated app.

A flexible template engine

DNA templates are basically virtual DOM nodes that check directly to the main tree to patch the DOM with an unintrusive strategy: if a new class or a new style property has been added to a node after the render, when the component updates DNA will not remove the rule unless it conflicts.

It also handles <slot> nodes like in Shadow DOM contexts but without really using Shadow DOM (and its polyfills): direct children are rendered to their correct position in the component's template.

It can also await promises and render response or subscribe to observables by automatically wrapping them into Functional components.

In order to provide a better interoperability with third party library, DNA can append, move or remove real Node instances in the template.

You don't need a compiler nor a bundler…

DNA is written in TypeScript and distributed for browsers, Node environments and bundlers. You can safely use it in the browser without having to compile components first, and thanks to template literals you can use the html helper to write standard templates with all the benefits of JSX.

… but they can be friends

As said before, the aim of DNA 3 is to bring a great Developer Experience for Web Components authors. For this reason, DNA comes with typings for the IDE, out of the box support for the new Babel JSX plugin, tree shaking of unused helpers and decorators for properties that works with both TypeScript and Babel. DNA runs with the bundler of your choice, with the transpiler of your choice and the IDE of your choice.

Give it a try

Follow the documentation or use the official sandbox to try out DNA.

Source code: https://github.com/chialab/dna
Home and documentation: https://www.chialab.io/projects/dna
Playground: https://stackblitz.com/edit/dna-3-sandbox

You can also use the unpkg.com CDN:

import { Component, customElements, html, property } from 'https://unpkg.com/@chialab/dna?module';

class HelloWorld extends Component {
    static get observedAttributes() {
        return ['name'];
    }

    static get listeners() {
        return {
            // delegate an event
            'change input[name="firstName"]': function() {
                this.name = target.value;
            },
        };
    }

    static get properties() {
        return {
            // define an observed property
            name: String,
        };
    }

    render() {
        return html`
            &lt;input name="firstName" value="${this.name}" />
            &lt;h1>Hello ${this.name || 'World'}!&lt;/h1>
        `;
    }
}

// link the Component class to a tag
customElements.define('hello-world', HelloWorld);

// render the Component
const app = document.getElementById('app');
render(html`&lt;${HelloWorld} />`, app);

Or installing it from the NPM registry:

npm i @chialab/dna

Thank you for reading! If you have any question or a feedback to share, we would happy to hear it!