I am trying to understand the newish HTML custom elements.
My goal is, given some array of data, create n instances of the custom element. For example, given a list of 10 users, create 10 user html objects.
Ok - so I define a custom element in the html
HTML
<template-user>
<div class="user-name"></div>
</template-user>
Then I create my controller
JS
class UserTemplate extends HTMLElement {
constructor(){
super();
this.username = this.querySelectorAll('[class="user-name"]')[0];
}
setName(name){
this.username.innerHtml = name;
}
}
customElements.define('template-user', UserTemplate);
The page loads fine, but now I am confused on how to reuse that element. If I was doing normal old school stuff, I'd have a for-loop pumping out some HTML strings and setting the innerHTML of something. But now I'd rather do something like
for(let i = 0; i < users.length; i++){
let userTemplate = new UserTemplate();
userTemplate.setName(user.name);
// append to user list, etc..
}
When I try to do this, it seems to almost work. But it cannot find username
, ie this.querySelectorAll
will return null. That's only when I try to construct a new instance of this element. How then, am I supposed to create new custom element DOM objects?
We can create custom HTML elements, described by our class, with its own methods and properties, events and so on. Once a custom element is defined, we can use it on par with built-in HTML elements.
The bread and butter of Web Components are custom elements. The customElements API gives us a path to define custom HTML tags that can be used in any document that contains the defining class. Think of it like a React or Angular component (e.g. ), but without the React or Angular dependency.
There are two types of custom elements: Autonomous custom elements are standalone — they don't inherit from standard HTML elements. You use these on a page by literally writing them out as an HTML element. For example <popup-info>, or document.createElement ("popup-info"). Customized built-in elements inherit from basic HTML elements.
We can extend and customize built-in HTML elements by inheriting from their classes. For example, buttons are instances of HTMLButtonElement, let’s build upon it. Provide the third argument to customElements.define, that specifies the tag:
Make sure you understand the requirements and limitations of constructors for Web Components:
https://html.spec.whatwg.org/multipage/custom-elements.html#custom-element-conformance
4.13.2 Requirements for custom element constructors
When authoring custom element constructors, authors are bound by the following conformance requirements:
Several of these requirements are checked during element creation, either directly or indirectly, and failing to follow them will result in a custom element that cannot be instantiated by the parser or DOM APIs. This is true even if the work is done inside a constructor-initiated microtask, as a microtask checkpoint can occur immediately after construction.
You could make changes similar to this:
class TemplateUser extends HTMLElement {
static get observedAttributes() {
return ['user-name'];
}
constructor(){
super();
this.attachShadow({mode:'open'});
this.shadowRoot.innerHTML = '<div></div>';
}
attributeChangedCallback(attrName, oldVal, newVal) {
if (oldVal !== newVal) {
this.shadowRoot.firstChild.innerHTML = newVal;
}
}
get userName() {
return this.getAttribute('user-name');
}
set userName(name) {
this.setAttribute('user-name', name);
}
}
customElements.define('template-user', TemplateUser);
setTimeout( function () {
var el = document.querySelector('[user-name="Mummy"]');
el.userName = "Creature from the Black Lagoon";
}, 2000);
<template-user user-name="Frank N Stein"></template-user>
<template-user user-name="Dracula"></template-user>
<template-user user-name="Mummy"></template-user>
This uses shadowDOM to store a <div>
, then you set the value through the user-name
attribute or through the userName
property.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With