Skip to content
Components for the DOM as you've never seen before
Branch: master
Clone or download
Latest commit c3e4473 May 17, 2019

README.md

wickedElements

Social Media Photo by Jonatan Pie on Unsplash

Build Status Greenkeeper badge WebReflection status

Bringing the regularElements goodness to a component based world.

  • no fancy polyfills needed for IE11+, it optionally works even in IE9
  • lightweight as in ~2K lightweight, with also a 1.7K brotli version, for modern browsers only, that drops all unnecessary polyfills for WeakSet, CustomEvent, element.matches(...) or Object.assign 🎉
  • CPU & RAM friendly (100% based on handleEvent through prototypal inheritance)
  • components can exist at any time (past, present, future)
  • no issues with classes, it works well with composed behaviors
  • you can use classes if you like anyway, just pass one instead of a literal!
  • you can use wicked elements as an alternative custom elements polyfill in combination with own element names (e.g. my-wicked-element)
  • you can define multiple behaviors, per same DOM element, through the power of CSS selectors
  • lazy load any component at any time: all their states are uniquely private per selector and per node
  • either attributeFilter or observedAttributes can be used to observe specific attributes

How to

  • as CDN global object, via <script src="https://unpkg.com/wicked-elements"></script>
  • as ESM module, via import wickedElements from 'wicked-elements'
  • as CJS module, via const wickedElements = require('wicked-elements');

API

Same regularElements API, meaning same customElements API.

// either via classes (ES2015+)
// wickedElements.define('.is-wicked-element', class { ... });
// or literals (ES5+)
wickedElements.define('.is-wicked-element', {

  // always triggered once a node is live (even with classes)
  // always right before onconnected and only once,
  // ideal to setup anything as one off operation
  init: function (event) {
    // the context is actually a private object
    // that inherits the component definition
    // literally: Object.create(component)
    this.el = event.currentTarget;
    // accordingly, you can attach any property
    // and even if public, these won't ever leak
    // (unless you decide to leak the component)
    this._rando = Math.random();
    // you can invoke directly any method
    this.render();
  },

  // regularElements hooks available
  onconnected(event) {},
  ondisconnected(event) {},
  onattributechanged(event) {},

  // and any other event too
  // just prefix a method with `on` and it will
  // be automatically setup for listening
  onclick(event) {},

  // define optional options for specific events
  // any `on${event.type}Options` would work
  onclickOptions: {once: true},

  // if there is a style, it'll be injected only once per component
  // inherited styles won't get injected, and classes needs
  // a static get style() { return '...'; } if this behavior is needed
  style: `
    .is-wicked-element {
      border: 2px solid silver;
    }
  `,

  // works well with any 3rd parts library
  // WARNING: THIS IS JUST AS EXAMPLE,
  //          YOU DON'T NEED hyperHTML
  //          TO USE THIS LIBRARY!
  //          THE NODE CAN BE ANY NODE
  //          AND ALREADY POPULATED WITH CONTENT
  render() {
    this.html`<p>I am rando ${this._rando}</p>`;
  },

  // any object literal syntax available out of the box
  // it's 100% based on prototypal inheritance
  get html() {
    return hyperHTML.bind(this.el);
  }
});

// you can also attach the wicked element behaviour to
// custom element names without needing customElements
wickedElements.define('wicked-element', {
  // ...
});

// or even ...
wickedElements.define('[is="wicked-element"]', {
  // ...
});

Attributes

These are examples to listen to specific attributes:

// with JS literals
wickedElements.define('...', {
  // ...
  observedAttributes: ['only', 'these'],
  // **OR**
  attributeFilter: ['only', 'these']
  // ...
});

// with ES classes
wickedElements.define('...', class {
  // ...
  static get observedAttributes() {
    return ['only', 'these'];
  }
  // **OR**
  get attributeFilter() {
    return ['only', 'these'];
  }
  // ...
});

Bear in mind, if the array is empty all attributes changes will be notified.

You can’t perform that action at this time.