The following code works fine with Firefox, but is buggy with Chrome.
I have a tst-list web component. In it is a tst-add component, which looks like a plus icon, with id ADD. When one clicks the add button (#ADD plus icon), it will create a tst-wrapper component and add it to the tst-list component. Each tst-wrapper item will show a PREV and NEXT button if appropiate, for re-ordering. If an items is first, it will NOT show a PREV, if the items is last, it will not show a NEXT button.
NOT WORKING RESULT
This is what the output looks like (after clicking #ADD 5 times), when NOT working (the NEXT button never shows):
WORKING RESULT
And when working:
I have identified a styling issue and a hack to make it work, detailed in the following 2 sections:
STYLING ISSUE
This styling of the ADD icon makes last-of-type not work. So if I remove this styling, it works, In particular the CSS selector is the issue. However I would like this styling:
:host(:active) #ICON {
fill: red;
}
HACK
If one hides then shows the previous last-of-type element, it seems to give the CSS a kick and it renderes correctly, in the code example, uncommenting the hack as shown below will make it work:
// --- START OF HACK
child.previousElementSibling.style.display="none"
setTimeout(() =>child.previousElementSibling.style.display="block");
// --- END OF HACK
MINIMAL REPRODUCIBLE EXAMPLE
customElements.define('tst-add', class extends HTMLElement {
constructor() {
super().attachShadow({mode: 'open'})
.append(document.getElementById('TEMPLATE_add').content.cloneNode(true));
}
});
customElements.define('tst-wrapper', class extends HTMLElement {
constructor() {
super().attachShadow({mode: 'open'})
.append(document.getElementById('TEMPLATE_wrapper').content.cloneNode(true));
}
});
const WRAPPER_LOCAL_NAME = 'tst-wrapper';
customElements.define('tst-list', class extends HTMLElement {
constructor() {
super().attachShadow({mode: 'open'})
.append(document.getElementById('TEMPLATE_list').content.cloneNode(true));
this.shadowRoot.getElementById('ADD')
.addEventListener('click', (evt) => this.addChild(evt));
}
addChild(evt) {
const child = document.createElement(WRAPPER_LOCAL_NAME);
child.textContent = "NEW"
this.appendChild(child);
if (child.previousElementSibling) {
// --- START OF HACK
//child.previousElementSibling.style.display="none"
//setTimeout(() =>child.previousElementSibling.style.display="block");
// --- END OF HACK
}
}
});
<template id="TEMPLATE_add">
<style>
:host(:active) #ICON {
fill: red;
}
</style>
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000" draggable="false" id="ICON">
<path d="M0 0h24v24H0z" fill="none"></path>
<path d="M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-2 10h-4v4h-2v-4H7v-2h4V7h2v4h4v2z"></path>
</svg>
</template>
<template id="TEMPLATE_wrapper">
<style>
:host(:first-of-type) #PREV,
:host(:last-of-type) #NEXT {
display: none;
}
</style>
<div id="CONTAINER">
<slot></slot>
<button id="PREV" type="button">PREV</button>
<button id="NEXT" type="button">NEXT</button>
</div>
</template>
<template id="TEMPLATE_list">
<div id="CONTAINER">
<div id="LIST" part="list">
<slot id="SLOT"></slot>
</div>
<tst-add id="ADD"></tst-add>
</div>
</template>
<tst-list></tst-list>
Using Chrome v109


classattributes instead, but that doesn't solve the issue. Give it a little more time so better minds than mine can maybe chime in, but otherwise it indeed looks like a Chrome bug.