Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Display as much elements as it can fit in one line, and if not all of them can fit add additional element that represents number of remaining elements

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:

enter image description here

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:

enter image description here

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>
like image 788
NeNaD Avatar asked Oct 22 '25 11:10

NeNaD


2 Answers

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.

like image 185
ruleboy21 Avatar answered Oct 25 '25 02:10

ruleboy21


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).

like image 29
Jelmertje Avatar answered Oct 25 '25 02:10

Jelmertje



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!