dna-poster

DNA

Progressive Web Components.

Get started

The recommended way to use DNA is to setup an ES7 project with Babel or TypeScript which has a lot of life saver features like modules, decorators and typechecking, but it can also work without transpilers and bundlers directly in the browser.

Use a CDN

You can use DNA via CDN thanks to the Unpkg project, which exposes a global DNA namespace if fetched via script tag, or the ES module with ?module param:

<script src="https://unpkg.com/@chialab/dna"></script>
import { Component, customElements } from 'https://unpkg.com/@chialab/dna?module';
Setup a bundler

The DNA environment is pretty common (if you are familiar with other libraries like React, Angular, LitElement etc.):

  1. Make sure you have a recent Node.js version installed

  2. Setup a bundler (Rollup is recommended, but Webpack and Parcel are equally good choices)

  3. Setup Babel (Rollup, Webpack, Parcel) or TypeScript (Rollup, Webpack, Parcel):

    • if your choice is Babel, please make sure all this plugins are loaded in order to use all DNA features:

      $ npm i -D \
            @babel/plugin-proposal-decorators \
            @babel/plugin-proposal-class-properties

      .babelrc

      {
            "plugins": [
                "@babel/plugin-proposal-decorators",
                "@babel/plugin-proposal-class-properties"
            ]
        }

      If you want to use React JSX instead of template strings, you will also need to install the @babel/plugin-transform-react-jsx:

      {
            "plugins": [
                ...
                ["@babel/plugin-transform-react-jsx", {
                    // "pragma": "h",
                    "runtime": "automatic",
                    "importSource": "@chialab/dna"
                }]
            ]
        }

      Since the DNA html method is provided by the htm module by Jason Miller, you can also use the babel-plugin-htm to preprocess templates.

      {
            "plugins": [
                ...
                ["babel-plugin-htm", {
                    "pragma": "h",
                    "import": {
                        "module": "@chialab/dna"
                    }
                }]
            ]
        }
  4. Install DNA

    $ npm i @chialab/dna

Define a component

DNA components are classes which extends the base HTMLElement with helpers for templating, styling, events delegation and life cycle.

Defining a component means to link a HTML tag with the element's constructor, as described by the Custom Elements specification. In this example we are going to use the customElements.define method to register the component in the DNA registry:

import { Component, customElements, html } from '@chialab/dna';

// create a component class
class HelloWorld extends Component {
    // define a template
    render() {
        return html`<h1>Hello world!</h1>`;
    }
}

// link the HTML tag with the class
customElements.define('hello-world', HelloWorld);
Extending native elements

In the Custom Element specification it is possible to define an element using the is attribute instead of the tag (unfortunately, no browser vendor had implemented it at the moment). This is very useful when you want to extend a HTML tag, preserving its semanthic meaning. An example:

import { Component, customElements, html, property } from '@chialab/dna';

class BlogPost extends Component {
    static get observedAttributes() {
        return ['title'];
    }

    @property() title = '';

    render() {
        return html`<h1>${this.title}</h1>`;
    }
}

// extend the article tag
customElements.define('blog-post', BlogPost, {
    extends: 'article'
});

In the example above, a new instance of BlogPost inherits all class methods and properties, but its tagName will be ARTICLE.

 Render a component

The render helper is used by DNA components to generate their templates, but it can be used to add a component or a template in a specific point of the DOM tree, for example to instantiate the root component of your application:

import { Component, customElements, render } from '@chialab/dna';

class Card extends Component {
    ...
}

customElements.define('x-card', Card);

render(new Card(), document.body);

During the render cycle, DNA execs an in-place DOM diffing to update already existing nodes and remove the unused ones, so you can safely re-render a template.

This function accepts the render root node as first argument and a node or a template as second one. Another way to instantiate the Card component is:

import { Component, customElements, html, render } from '@chialab/dna';

class Card extends Component {
    ...
}

customElements.define('x-card', Card);

render(html`<x-card />`, document.body);

It also work for extended native tags:

import { Component, customElements, html, render } from '@chialab/dna';

class Article extends Component {
    ...
}

customElements.define('x-article', Article, { extends: 'article' });

render(html`<article is="x-article" />`, document.body);

You can use the render method to inject more complex templates too:

import { render, html } from '@chialab/dna';

render(html`<div class="wrapper">
    <h1>Title</h1>
</div>`, document.body);