In the MDN documentation for using custom elements, they detail an example for customizing built-in elements:
customElements.define('expanding-list', ExpandingList, { extends: "ul" });
Allowing this usage:
<ul is="expanding-list">
...
</ul>
I am wondering if it is possible to customize another custom element in the same way? For example, if I have created an element called custom-element
, and I want to have variants of it, I might want to create a new special-custom-element
class, and define it in the same way, so as to be able to use it like so:
<custom-element is="special-custom-element">
...
</custom-element>
However, I am prompted with an error stating:
Uncaught DOMException: Failed to execute 'define' on 'CustomElementRegistry': "custom-element" is a valid custom element name
When attempting to run the following:
customElements.define('special-custom-element', SpecialCustomElement, { extends: 'custom-element' });
Is this something I am doing wrong, or is this behaviour strictly limited to built-in elements? I'm finding it rather difficult to find any information about this behaviour other than what is on the page I linked to, so I was hoping for some advice from someone who knows the specs better.
You can not do it in the sense that you want since:
There are two types of custom elements you can create:
Autonomous custom element: Standalone elements; they don't inherit from built-in HTML elements.
Customized built-in element: These elements inherit from — and extend — built-in HTML elements.
customElements.define('word-count2', WordCount2, {extends: 'p'});
Is for extending the built-in elements
.
You have to go the Autonomous custom element
route as per the docs
Here is an idea:
// Create a class for the element
class MyElement extends HTMLElement {
constructor(text) {
// Always call super first in constructor
super();
// Create a shadow root
var shadow = this.attachShadow({
mode: 'open'
});
// Create the span
var wrapper = document.createElement('span');
wrapper.textContent = !!text ? text : 'foo';
shadow.appendChild(wrapper);
}
}
class MyElement2 extends MyElement {
constructor() {
// Always call super first in constructor
super('bar');
}
}
// Define the new element
customElements.define('my-element', MyElement);
customElements.define('my-element2', MyElement2);
<div>
<my-element text="">
</div>
<div>
<my-element2 text="">
</div>
Now you still could extend your class (and do customization of a build-in element) and access the output of the super
so that might be useful to you and to some extend might allow you to get what you need:
// Create a class for the element
class WordCount extends HTMLParagraphElement {
constructor() {
// Always call super first in constructor
super();
// count words in element's parent element
const wcParent = this.parentNode;
function countWords(node) {
const text = node.innerText || node.textContent;
return text.split(/\s+/g).length;
}
const count = `Words: ${countWords(wcParent)}`;
// Create a shadow root
const shadow = this.attachShadow({
mode: 'open'
});
// Create text node and add word count to it
const text = document.createElement('span');
text.textContent = count;
// Append it to the shadow root
shadow.appendChild(text);
// Update count when element content changes
text.textContent = count;
}
}
class WordCount2 extends WordCount {
constructor() {
// Always call super first in constructor
super();
console.log(this.shadowRoot.textContent)
}
}
// Define the new element
customElements.define('word-count', WordCount, {
extends: 'p'
});
customElements.define('word-count2', WordCount2, {
extends: 'p'
});
<div>
<h2>Sample heading</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc pulvinar sed justo sed viverra. Aliquam ac scelerisque tellus. Vivamus porttitor nunc vel nibh rutrum hendrerit. Donec viverra vestibulum pretium. Mauris at eros vitae ante pellentesque bibendum.
Etiam et blandit purus, nec aliquam libero. Etiam leo felis, pulvinar et diam id, sagittis pulvinar diam. Nunc pellentesque rutrum sapien, sed faucibus urna sodales in. Sed tortor nisl, egestas nec egestas luctus, faucibus vitae purus. Ut elit nunc,
pretium eget fermentum id, accumsan et velit. Sed mattis velit diam, a elementum nunc facilisis sit amet.</p>
<p is="word-count"></p>
</div>
<div>
<h3>Sample heading</h3>
<p>Lorem ipsum dolor sit amet, consec Sed tortor nisl, egestas nec egestas luctus, faucibus vitae purus. Ut elit nunc, pretium eget fermentum id, accumsan et velit. Sed mattis velit diam, a elementum nunc facilisis sit amet.</p>
<p is="word-count2"></p>
</div>