CE-DECORATORS
ce-decorators is a typescript library for custom element development. It is powered by lit-html for effective DOM updates. The decorator API is similar to stenciljs but without the need of a special compiler, just the ts-compiler is needed.
The decorators will take care of style registering if the ShadyCSS scoping shim is needed, attribute-property reflection with type transformation from attribute to property and vice versa. All in just 14kb (26kb with lit-html bundled).
Custom elements
Custom elements are user defined HTML elements, which offer customized functionalities and styling. When used inide an HTML template it looks like this:
Click this Button
In this example custom-button
is the tag-name of the element, primary is a specific attribute and Click this button is a slot element passed in the element for further processing.
For detailed information about custom elements see
https://developers.google.com/web/fundamentals/web-components/
Compatibility
The library is compatible with IE11 (needs babel transpile), Chrome, FF, Edge, Safari and the mobile Safari and Chrome Browser.
For IE11 you need: @webcomponents/webcomponentsjs
polyfills and Polyfills for Symbol
, Map
, WeakMap
and Promises
For Edge you need: @webcomponents/webcomponentsjs
in FF, Safari and Chrome everything should just work.
If you compile all down to ES5 you need for all Brwosers the custom-elements-es5-adapter.js
.
Benefits
- No boilerplate code
- Code completion since all properties are named and have types
Installation
npm install ce-decorators
important! you need the following compiler settings in your tsconfig.json
"emitDecoratorMetadata": true,"experimentalDecorators": true
Usage
babel dependencies (for ES5):
"@babel/plugin-proposal-class-properties": "^7.0.0","@babel/plugin-proposal-decorators": "^7.0.0","@babel/preset-env": "^7.0.0","@babel/preset-typescript": "^7.0.0", (optional only when using typescript)
babel config:
plugins: "@babel/plugin-proposal-decorators" legacy: true/false "@babel/plugin-proposal-class-properties" "loose" : true
Both decorator specification (Stage-0 and Stage-2 are supported).
If decorators are used with babel the data type for the Prop decorator has to be specified, otherwise attribute reflection won't work.
Sample
;
Lifecycle
Construction/rendering
- constructor call
- resolve promise returned by waitForConstruction() on custom element (awaitable)
- <append to dom>
- componentConnected()
- <if a property changed or first connect deferred in microtask (in asnyc task if you use
LazyCustomElement
)> - componentWillRender(): property changes within this function will be taken into account in the rendering step
- render()
- componentDidRender(): can be used for post-processing runs in the same asnyctask/microtask as render
- resolve promise returned by waitForRender() on custom element (awaitable)
- <if property or attribute changed (deferred in microtask)>
- render() deferred in microtask or in asnyc task if you use
LazyCustomElement
- <remove/detach from dom>
- componentDisconnected()
In code
;await element.waitForForConstruction; element.propertyOne = 'test'; // will be reflected as property-one attributedocument.querySelector'body'.appenChildelement; // element.componentConnected() calledawait element.waitForRender; // element.componentWillRender() called // element.render() called // element.componentFirstRender() called *only called on first render* // element.componentDidRender() calleddocument.querySelector'body'.removeChildelement; // element.componentDisconnected() called
Because render calls are deferred into a microtask or async task, setting multiple attributes/properties consecutively will result in just one render call.
Property updates
- set property myProperty
- run interceptors
- if reflectToAttribute is set for myProperty (or undefined, which is the default case), the property will be reflected as attribute my-property
- notify watchers
- deffer render() to microtask (so if multiple attributes/properties are set in the same task, render is only called once)
LazyCustomElement
LazyCustomElement
is an alternative to the default CustomElement
which renders in an asnyc task (setTimeout
) instead of a microtask .
Usage
Use with Angular
For angular CUSTOM_ELEMENTS_SCHEMA
needs to be activated. Now custom elements can be used like angular components.
in the component:
in the template:
Use with react
In react you need to pass everything as attributes
import 'my-custom-element';