DEV Community

Cover image for So, you can't use CustomElements and don't want polyfills for whatever reasons, are there any workarounds ?  yes :-)
artydev
artydev

Posted on

So, you can't use CustomElements and don't want polyfills for whatever reasons, are there any workarounds ? yes :-)

There is indeed a workaround for this. Andrea made an enhanced version of RegularElements showed in a previous post. It's called WickedElements.
It can handle any element as if It was a customElement.

You cant test it Here : Counter

Here is the ToDoMVC example from Andrea

Here is a how you define a 'wicked-element' :

wickedElements.define(
  // a unique, specific, CSS selector that will become wicked
  '[data-wicked="my-component"]',
  {
    // a one-off, `constructor` like, initialization,
    // the right place to populate node content, add listeners, or setup components
    init() {
      // the element that is related to this wicked instance will be always
      // reachable through `this.element`, even without an `init()` method
      this.element;
      // always points, in every other method, to the DOM element related
      // to this wicked element/component
    },

    // Custom Elements like callbacks, without the redundant `Callback` suffix
    connected() {},
    disconnected() {},

    // invokes `attributeChanged` if any of these attributes is changed, set, removed
    observedAttributes: ['data-thing', 'value'],
    attributeChanged(name, oldValue, newValue) {},

    // zero, one, or more, listeners, automatically setup per each component
    // the context of each method-listener will be the wicked instance,
    // not the element itself, but you can reach event.currentTarget or this.element
    // at any time within the code
    onClick(event) {},
    onCustomEvent(event) {}
    // if defined camelCase, events will be attached both lowercase
    // and also camelCase, so that element.dispatch(new CustomEvent('customEvent'))
    // or element.dispatch(new CustomEvent('customevent')) will both work.
    // the `event.type` will be the one dispatched, i.e. `click` or `customEvent`
    // or even `customevent`.

    // any property with an `Options` suffix, will be used to add the listener,
    // so that special cases like `{once: true}`, `true` to capture, and others,
    // can be easily addressed through the definition. By default, options is `false`.
    onClickOptions: {once: true}
  }
);
Enter fullscreen mode Exit fullscreen mode

The 'Hello World' of customElements seems to be the famous Counter.
Here is how you can implement it :

wickedElements.define('.my-counter', {
  init() {
    this.counter = this.element.querySelector('.count');
    this.counter.textContent = (this.count = 0);
  },
  onClick({target}) {
    switch (true) {
      case target.classList.contains('minus'):
        this.counter.textContent = --this.count;
        break;
      case target.classList.contains('plus'):
        this.counter.textContent = ++this.count;
        break;
    }
  }
});

Enter fullscreen mode Exit fullscreen mode

HTML

<div class="my-counter">
  <button class="large minus">-</button>
  <span class="large count">0</span>
  <button class="large plus">+</button>
</div>
<hr>
<div class="my-counter">
  <button class="large minus">-</button>
  <span class="large count">0</span>
  <button class="large plus">+</button>
</div>
Enter fullscreen mode Exit fullscreen mode

CSS

body { text-align: center; }
.my-counter .large { font-size: 200%; }
.my-counter .count {
  width: 4rem;
  display: inline-block;
  text-align: center;
  color: black;
}
.my-counter > button {
  width: 64px;
  height: 64px;
  border: none;
  border-radius: 10px;
  background-color: seagreen;
  color: white;
}

Enter fullscreen mode Exit fullscreen mode

Top comments (0)