I have a jQuery plugin (which I don't want to modify) that is dynamically creating a div
. Aside from that, I have a webcomponent scrollable-div
, which is a customized built-in extended from HTMLDivElement
. As I have no control over how that div
is created by the jQuery plugin, I need to upgrade it after creation and after it has already been added to the DOM.
class myDiv extends HTMLDivElement {
constructor(...args) {
const self = super(...args);
self.addEventListener('click', (e) => {
e.target.textContent = 'clicked'
})
return self;
}
}
customElements.define('my-div', myDiv, { extends: 'div' });
document.addEventListener('DOMContentLoaded', () => {
// this is where I'm trying to turn the div#upgradeMe into a my-div
upgradeMe.setAttribute('is', 'my-div');
});
<div id="upgradeMe">Click me</div>
Simply adding the is="my-div"
attribute obviously does not do the trick, the div
simply stays a regular HTMLDivElement
. How can I programmatically upgrade a native element that is already in the DOM to a customized built-in web component?
It's not possible because the element is already created as a standard <div>
element and not identified when parsed as upgradable (extendable) due to the lack of the is
attribute.
If the custom element is already defined, the only possible workaround is to replace the existing by a clone (as suggested in the comments by @barbsan).
The short way:
<template>
elementouterHTML
into its innerHTML
propertycontent
with replaceChild()
class myDiv extends HTMLDivElement {
constructor(...args) {
const self = super(...args);
self.addEventListener('click', (e) => {
e.target.textContent = 'clicked'
})
return self;
}
}
customElements.define('my-div', myDiv, { extends: 'div' });
document.addEventListener('DOMContentLoaded', () => {
// this is where I'm trying to turn the div#upgradeMe into a my-div
upgradeMe.setAttribute('is', 'my-div');
var t = document.createElement( 'template' )
t.innerHTML = upgradeMe.outerHTML
upgradeMe.parentElement.replaceChild( t.content, upgradeMe )
});
<div id="upgradeMe">Click me</div>
Précisions
When an element is parsed, an is value is affected according to the DOM spec:
Elements have an associated namespace, namespace prefix, local name, custom element state, custom element definition, is value. When an element is created, all of these values are initialized.
Only elements with a valid is
attribute are identified as customizable:
An element’s custom element state is one of "undefined", "failed", "uncustomized", or "custom". An element whose custom element state is "uncustomized" or "custom" is said to be defined. An element whose custom element state is "custom" is said to be custom.
Therefore if the element has no is
attribute at parse time, it will not be customizable. That's why you cannot add the is
attribute afterward.
Also in the HTML specs:
After a custom element is created, changing the value of the is attribute does not change the element's behavior, as it is saved on the element as its is value.
The is
attribute is used only at element creation (at parse time) to initialize the is value and has no effect if changed when the element is already created. In that sense is value is read-only.