Skip to content

Instantly share code, notes, and snippets.

@burawi
Last active January 15, 2021 13:37
Show Gist options
  • Save burawi/5656b54d8ed63573fb67b694458feb2a to your computer and use it in GitHub Desktop.
Save burawi/5656b54d8ed63573fb67b694458feb2a to your computer and use it in GitHub Desktop.
This is a proposal of a browser API that handles custom HTML attributes somehow like custom elements

Custom Attributes

This README describes a new feature proposal to ECMASCRIPT.

The feature consists of a browser API that handles custom html attributes.

Introduction

Custom html attributes, are aimed to fill some cases that are not handled by custom elements. It consists of adding reusable attributes that can be set to any html element.

Custom attributes should have a special notation (eg: starting by #), to distinguish them from normal attributes.

Defining a new custom attribute is made using a define function of customAttributes API. (like custom elements)

The define function takes two arguments, the attribute name and settings. The second argument (settings) is an object with three properties, each one is a function:

  • connectedCallback: run when the element is connected to DOM (at the same time of connectedCallback of custom element). Takes 2 args (value, element)
  • addedCallback: run when the attribute is added to an element. Takes 2 args (value, element)
  • changedCallback: run when the attribute is changed. Takes 2 args (oldValue, newValue, element)
  • removedCallback: run when the attribute is removed from an element. Takes 2 args (oldValue, element)

Usecases

Form elements setter

Let's suppose we want to make all form elements change their value on a certain event. Using custom elements we would, in the best way, create a custom element that extends every form element, and then call the wanted behaviour into every class we created. It would look like this: HTML:

<input is="custom-input" set-value-on="updateValues" name="name"/>
<output is="custom-output" set-value-on="updateValues" name="age"/>
<select name="city" set-value-on="updateValues" is="custom-select">
  <option>Sousse</option>
  <option>Makkah</option>
  <option>New York</option>
  <option>Tokyo</option>
  ...
</select>
<textarea is="custom-area" set-value-on="updateValues" name="description"></textarea>

Create the listener in a separate file, let's call it listener.js, with this content:

export default element => ({detail}) => {
  element.value = detail[element.name]; 
}

Then create custom-input.js with this content:

import listener from "listener";
class CustomInput extends HTMLInputElement {
  constructor() {
    super();
    this.listener = listener(this);
    this.eventName = this.getAttribute("set-value-on");
  }
  
  connectedCallback() {
    document.addEventListener(this.eventName, this.listener)
  }
  
  disconnectedCallback() {
    document.removeEventListener(this.eventName, this.listener)
  }
}
customElements.define('element-details', CustomInput);

And do that for every form element output select textarea

Syntax example

HTML:

<input #set-value-on="updateValues" name="name"/>
<output #set-value-on="updateValues" name="age"/>
<select name="city" #set-value-on="updateValues">
  <option>Sousse</option>
  <option>Makkah</option>
  <option>New York</option>
  <option>Tokyo</option>
  ...
</select>
<textarea #set-value-on="updateValues" name="description"></textarea>

Javascript:

const listener = element => ({ detail }) => { 
  element.value = detail[element.name]; 
};

let elementListener;
const connectedCallback = (eventName, element) => {
  elementListener = listener(element);
  document.addEventListener(eventName, elementListener);
}

const addedCallback = connectedCallback;
const removedCallback = (oldEventName, element) => {
  document.removeEventListener(oldEventName, elementListener);
}

const changedCallback = (oldEventName, newEventName, element) => {
  removedCallback(oldEventName, element);
  connectedCallback(newEventName, element);
}

customAttributes.define("#set-value-on", { connectedCallback, addedCallback, changedCallback, removedCallback })
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment