Skip to content
Custom Elements made available for any node, and through CSS selectors
JavaScript HTML
Branch: master
Clone or download
Latest commit 8fd1cdb Nov 22, 2019
Type Name Latest commit message Commit time
Failed to load latest commit information.
cjs improved wehnDefined resolution Apr 30, 2019
esm improved wehnDefined resolution Apr 30, 2019
test fixed tests for IE < 11 May 17, 2019
.gitignore first commit Nov 17, 2018
.npmignore first commit Nov 17, 2018
.travis.yml chore(travis): whitelist greenkeeper branches Nov 30, 2018
LICENSE first commit Nov 17, 2018
index.d.tx Add typescript definitions Nov 22, 2019
index.js updated disconnected May 24, 2019
min.js updated disconnected May 24, 2019
rollup.config.js massive cleanup using @ungap Dec 1, 2018


Build Status Greenkeeper badge WebReflection status

Everything I love about Custom Elements made available for any node, and through CSS selectors.

No Custom Elements, no Shadow DOM, forget about polyfills and classes, use just the good old HTML, exponentially glorified for every browser and in less than 2Kb library.

regularElements.define('button.alive', {
  // triggered once live
  // if defined later on and already live
  // it will trigger once (setup here)
  onconnected() {
    this.disabled = false;
  // triggered once lost/removed
  ondisconnected() {
  // triggered when any attribute changes
  onattributechanged(event) {
    const {attributeName, oldValue, newValue} = event;
    console.log(attributeName, oldValue, newValue);
  // optionally you can specify attributes to observe
  // by default, or with an empty list, all attributes are notified
  attributeFilter: ['only', 'these', 'attrs']

  '#complex > selector [data-available]',

// direct one-off element enhancement via

The API is similar to the customElements one, included .get(selector) and .whenDefined(selector).

What About Components ?

This module brings literally only those 3 primitives to the table, but fear not, wickedElements are a super thin wrapper that will bring 100% prototypal based components on top of these hooks, providing a private context per each component / node pair.

Trust me, the name wasn't chosen by accident, components made this way are absolutely wicked!


Even IE 9, but in order to also use whenDefined method, a Promise polyfill needs to be available on the global scope.

Following an example of how you could bring a Promise and WeakMap polyfill only in legacy browsers (IE9 and IE10), through a single script on top of any page that needs it.

<script>this.Promise||document.write('<script src=""><\x2fscript>')</script>
<script>this.WeakMap||document.write('<script src=""><\x2fscript>')</script>

Best Practices

Since, like it is for Custom Elements, you can define one selector per time, it is suggested to not use too generic selectors such a or button in case you'd like to compose behaviors.

A single node can indeed behave in various way, as long as it matches one or more defined selector.

regularElements.define('.clicker', {
  onconnected() {
    this.addEventListener('click', theClicker);
regularElements.define('.hi-five', {
  onconnected() {
    this.textContent += ' 🖐 ';

Whenever an element with either the class clicker, or hi-five, or both is created or found live on the DOM, it will be setup once per behavior, as demoed here.

You can’t perform that action at this time.