Get started
Install
DNA is published to the NPM registry
npm install @chialab/dna
yarn add @chialab/dna
pnpm add @chialab/dna
Configure Typescript
This enables support for DNA decorators as well as correct transpilation of class property fields.
{
"compilerOptions": {
"moduleResolution": "bundler",
"useDefineForClassFields": false,
"experimentalDecorators": true
}
}
Configure JSX
Typescript
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "@chialab/dna"
}
}
Babel
{
"plugins": [
[
"@babel/plugin-transform-react-jsx",
{
"runtime": "automatic",
"importSource": "@chialab/dna"
}
]
]
}
Define a component
DNA components are classes which extends the base HTMLElement
.
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 customElement
decorator method to register the component in the DNA registry:
import { Component, customElement, property } from '@chialab/dna';
@customElement('hello-world')
class HelloWorld extends Component {
@property() name: string = '';
render() {
return <h1>Hello {this.name || 'world'}!</h1>;
}
}
declare module '@chialab/dna' {
namespace JSX {
interface CustomElements {
'hello-world': HelloWorld;
}
}
}
import { Component, define, html } from '@chialab/dna';
const HelloWorld = define(
'hello-world',
class HelloWorld extends Component {
static get properties() {
return {
name: {
type: String,
defaultValue: '',
},
};
}
render() {
return html`<h1>Hello ${this.name || 'world'}!</h1>`;
}
}
);
INFO
TypeScript enables type checking and hints for component properties when you register the tag name with the JSX.CustomElements
interface in DNA.
Extending native elements
Custom Element specification allows to define an element using the is
attribute instead of the tag.
This is very useful when you want to extend a HTML tag, preserving its semanthic meaning. For example:
import { customElement, HTML, property } from '@chialab/dna';
@customElement('alert-dialog', {
extends: 'dialog',
})
class AlertDialog extends HTML.Dialog {
@property() title: string = '';
render() {
return <h1>{this.title}</h1>;
}
}
declare module '@chialab/dna' {
namespace JSX {
interface CustomElements {
'alert-dialog': AlertDialog & {
extends: 'dialog';
};
}
}
}
import { define, HTML, html } from '@chialab/dna';
const AlertDialog = define(
'alert-dialog',
class AlertDialog extends HTML.Dialog {
static get properties() {
return {
title: {
type: String,
defaultValue: '',
},
};
}
render() {
return html`<h1>${this.title}</h1>`;
}
},
{
extends: 'dialog',
}
);
In the example above, a new instance of AlertDialog
inherits all class methods and properties, but its tagName
will be DIALOG
.
INFO
Extending builtin elements also preserves accessibility and usability features: extending HTMLButtonElement
will make the component reachable and clickable via keyboard navigation without setting role
and tabindex
.
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, customElement, render } from '@chialab/dna';
@customElement('x-card')
class Card extends Component {
...
}
render(<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. At the end of the render cycle, DNA will remove any node outside the template, including elements and texts of the original HTML document.
This function accepts the template as first argument and an optional render root node as second one. You can also use bound tag name instead of constructor reference:
import { render } from '@chialab/dna';
import './Card';
import './Article';
render(
<>
<x-card />
<article is="x-article" />
</>,
document.body
);
import { Component, customElement } from '@chialab/dna';
@customElement('x-card')
class Card extends Component {
// ...
}
import { Component, customElement } from '@chialab/dna';
@customElement('x-article', {
extends: 'article',
})
class Article extends Component {
// ...
}