Web Components
The basics of the web-component plugin for Aurelia.
Introduction
Web Components are part of an ever-evolving web specification that aims to allow developers to create native self-contained components without the need for additional libraries or transpilation steps. This guide will teach you how to use Aurelia in Web Components.
Installing The Plugin
To use the plugin, import the interface IWcElementRegistry interface from @aurelia/runtime-html module and start defining web-component custom elements by calling method define on the instance of IWcElementRegistry.
WC custom elements can be defined anytime, either at the application start or later. Applications are responsible for ensuring names are unique.
Extending built-in elements is supported via the 3rd parameter of the define call, like the define call on the global window.customElements.define call.
How it works
Each of WC custom element will be backed by a view model, like a normal Aurelia element component.
For each
definecall, a corresponding native custom element class will be created and defined.Each bindable property on the backing Aurelia view model will be converted to a reactive attribute (via
observedAttributes) and reactive property (on the prototype of the extended HTML Element class created).Slot:
[au-slot]is not supported when upgrading an existing element.slotcan be used as a normal WC custom element.
Notes:
WC custom element works independently with the Aurelia component. This means the same class can be both a WC custom element and an Aurelia component. Though this should be avoided as it could result in double rendering.
containerlessmode is not supported. Use extend-built-in instead if you want to avoid wrappers.the defined WC custom elements will continue working even after the owning Aurelia application has stopped.
templateinfo will be retrieved & compiled only once perdefinecall. Changing it after this call won't have any effects.bindablesinfo will be retrieved & compiled only once perdefinecall. Changing it after this call won't have any effects.
Examples
Defining a
tick-clockelement
import { Aurelia, IWcElementRegistry } from 'aurelia';
Aurelia
.register(
AppTask.creating(IWcElementRegistry, registry => {
registry.define('tick-clock', class TickClock {
static template = '${message}';
constructor() {
this.time = Date.now();
}
attaching() {
this.intervalId = setInterval(() => {
this.message = `${Date.now() - this.time} seconds passed.`;
}, 1000)
}
detaching() {
clearInterval(this.intervalId);
}
})
})
)
.app(class App {})
.start();Defining a
tick-clockelement using shadow DOM withopenmode
import { Aurelia, IWcElementRegistry } from 'aurelia';
Aurelia
.register(
AppTask.creating(IWcElementRegistry, registry => {
registry.define('tick-clock', class TickClock {
static template = '${message}';
static shadowOptions = { mode: 'open' };
constructor() {
this.time = Date.now();
}
attaching() {
this.intervalId = setInterval(() => {
this.message = `${Date.now() - this.time} seconds passed.`;
}, 1000)
}
detaching() {
clearInterval(this.intervalId);
}
})
})
)
.app(class App {})
.start();Injecting the host element into the view model
import { INode, Aurelia, IWcElementRegistry } from 'aurelia';
Aurelia
.register(
AppTask.creating(IWcElementRegistry, registry => {
registry.define('tick-clock', class TickClock {
static template = '${message}';
static shadowOptions = { mode: 'open' };
// all these injections result in the same instance
// listing them all here so that applications can use what they prefer
// based on HTMLElement
static inject = [INode, Element, HTMLElement];
constructor(node, element, htmlElement) {
node === element;
element === htmlElement;
this.time = Date.now();
}
attaching() {
this.intervalId = setInterval(() => {
this.message = `${Date.now() - this.time} seconds passed.`;
}, 1000)
}
detaching() {
clearInterval(this.intervalId);
}
})
})
)
.app(class App {})
.start();Defining a
tick-clockelement withformatbindable property for formatting
import { INode, Aurelia, IWcElementRegistry } from 'aurelia';
document.body.innerHTML = '<tick-clock format="short"></tick-clock>';
Aurelia
.register(
AppTask.creating(IWcElementRegistry, registry => {
registry.define('tick-clock', class TickClock {
static template = '${message}';
static shadowOptions = { mode: 'open' };
static bindables = ['format'];
// all these injections result in the same instance
// listing them all here so that applications can use what they prefer
// based on HTMLElement
static inject = [INode, Element, HTMLElement];
constructor(node, element, htmlElement) {
node === element;
element === htmlElement;
this.time = Date.now();
}
attaching() {
this.intervalId = setInterval(() => {
this.message = `${(Date.now() - this.time)/1000} ${this.format === 'short' ? 's' : 'seconds'} passed.`;
}, 1000)
}
detaching() {
clearInterval(this.intervalId);
}
})
})
)
.app(class App {})
.start();Defining a
tick-clockelement extending built-indivelement:
import { Aurelia, IWcElementRegistry } from 'aurelia';
document.body.innerHTML = '<div is="tick-clock"></div>'
Aurelia
.register(
AppTask.creating(IWcElementRegistry, registry => {
registry.define('tick-clock', class TickClock {
static template = '${message}';
constructor() {
this.time = Date.now();
}
attaching() {
this.intervalId = setInterval(() => {
this.message = `${Date.now() - this.time} seconds passed.`;
}, 1000)
}
detaching() {
clearInterval(this.intervalId);
}
})
}, { extends: 'div' })
)
.app(class App {})
.start();Last updated
Was this helpful?