I would like to align all tags for a given article in one line.
If all the tags can fit in one line, then I want to display all of them, like this:

But, if there is more tags and not all of them can fit in the same line, I would like to display as much of them as it can fit, and I want to add additional label that represents number of remaining tags, like this:

I created this quick start code so everyone can jump and update what is necessary.
.card {
padding: 5px;
width: 300px;
height: 300px;
border: 2px solid blue;
display: flex;
flex-direction: row;
gap: 5px;
}
.tag {
padding: 5px 8px;
color: #2C3C93;
background: rgb(44, 60, 147, 0.1);
height: 20px;
}
<div class="card">
<div class="tag">Developing</div>
<div class="tag">Busniess</div>
<div class="tag">Web Design</div>
</div>
Try this
let cardWidth = document.querySelector('.card').offsetWidth; // or 300
let tagsWidth = 0;
let hiddenItems = 0;
document.querySelectorAll('.tag').forEach(tag => {
tagsWidth += tag.offsetWidth;
if( tagsWidth + 60 > cardWidth ){
hiddenItems++;
tag.style.display = 'none';
}
})
if( hiddenItems > 0 ){
document.querySelector('.card').insertAdjacentHTML('beforeend', `<div class="tag">${hiddenItems}+</div>`)
}
*,*::before,*::after {
box-sizing: border-box;
}
.card {
padding: 5px;
width: 300px;
height: 300px;
border: 2px solid blue;
display: flex;
align-items: flex-start;
gap: 5px;
}
.tag {
padding: 5px 8px;
color: #2C3C93;
background: rgb(44, 60, 147, 0.1);
white-space: nowrap;
}
<div class="card">
<div class="tag">Developing</div>
<div class="tag">Busniess</div>
<div class="tag">Web Design</div>
</div>
Please note that the 60 here tagsWidth + 60 is the width of the "remaining/hidden tags div". This is to ensure that there is enough room for the "remaining/hidden tags div" if the tagsWidth exceeds the cardWidth.
Here is my attempt: https://jsfiddle.net/oneuj3yv/28/
const counterElementWidth = 30;
function collapseTags() {
document.querySelectorAll('.card').forEach(card => {
let counterTag = card.querySelector('.counter-tag');
let cardStyle = getComputedStyle(card);
let padding = parseFloat(cardStyle.paddingLeft) + parseFloat(cardStyle.paddingRight);
let innerWidth = card.clientWidth - padding;
let usedWidth = 0;
let tagsLeft = 0;
card.querySelectorAll('.tag').forEach(tag=>{
usedWidth += tag.getBoundingClientRect().width;
if(usedWidth >= innerWidth - counterElementWidth) {
tag.classList.add('hidden');
tagsLeft++;
} else {
tag.classList.remove('hidden');
}
});
if(tagsLeft > 0) {
counterTag.classList.remove('hidden');
counterTag.innerHTML = `+${tagsLeft}`;
} else {
counterTag.classList.add('hidden');
}
});
}
collapseTags();
window.addEventListener('resize', collapseTags);
For the whole thing to work I have added some CSS and additional HTML to the fiddle as well.
It still seems a bit hit-or-miss on resize, but on load it works.
An improvement could be for the counter element to be dynamically generated.
Another future improvement could be the tweaking of counterElementWidth I used for the width of the counter (currently I just take a wild guess of 30 px).
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