JSFiddle - React, Tailwind, and code Playground
HTML
<!DOCTYPE html>
<html>
<body>
<app-tags style="max-height: 80px;">
<span class="card">Card 1</span>
<span class="card">Card 2</span>
<span class="card">Card 3</span>
<span class="card">Card 4</span>
<span class="card">Card 5</span>
<span class="card">Card 6</span>
<span class="card">Card 7</span>
<span class="card">Card 8</span>
<span class="card">Card 9</span>
<span class="card">Card 10</span>
</app-tags>
</body>
</html>
CSS
app-tags {
display: flex;
flex-direction: row;
flex-wrap: wrap;
overflow: hidden;
gap: 12px;
border: 1px solid red;
}
app-tags > * {
min-width: 0;
}
app-tags > .app-tags-badge {
position: absolute;
padding: 6px;
}
.card {
padding:6px;
border: 1px solid #ccc;
border-radius: 6px;
}
JavaScript
class Tags extends HTMLElement {
#observer = null;
#badge = document.createElement('span');
connectedCallback(){
this.#observer = new ResizeObserver(this.#update.bind(this));
this.#observer.observe(this);
this.#badge.classList.add('app-tags-badge');
this.appendChild(this.#badge);
}
disconnectedCallback(){
this.#observer?.disconnect();
}
#update(){
const p = this.getBoundingClientRect();
let hidden = 0;
let lastVisible = null;
this.childNodes.forEach(n => {
if(n instanceof HTMLElement && n !== this.#badge){
const c = n.getBoundingClientRect();
if(p.left > c.left || p.right < c.right || p.top > c.top || p.bottom < c.bottom){
hidden++;
n.style.visibility = 'hidden';
}else {
n.style.visibility = '';
lastVisible = n;
}
}
});
if(hidden < 1){
this.#badge.style.display = 'none';
}else if(lastVisible !== null){
lastVisible.style.visibility = 'hidden';
this.#badge.style.display = '';
this.#badge.style.top = `${lastVisible.offsetTop}px`;
this.#badge.style.left = `${lastVisible.offsetLeft}px`;
}else {
this.#badge.style.display = '';
this.#badge.style.top = '0';
this.#badge.style.left = '0';
}
this.#badge.innerHTML=`+${hidden} more`;
}
}
window.customElements.define('app-tags',Tags);