Cauder
Cauder

Reputation: 2597

Adjust the width of dropdown according to the length of the text

I have a dropdown option. Here's my code -

    <span class="header"> COMPARE </span>
        <span class="dropdown">
            <select class="select_box" id="opts">
                <p></p>
                <option value="default">Select a dataset</option>
                <option value="population">POPULATION</option>
                <option value="popdensityperacre">POPULATION DENSITY</option>
                <option value="percapitaincome">INCOME</option>
            <option value="percentnonwhite">RACIAL DIVERSITY</option>
            <option value="percentinpoverty">POVERTY</option>
            <option value="medianhomevalue">HOME VALUE</option>
            <option value="unemploymentrate">UNEMPLOYMENT</option>
            <option value="percapitacriminalarrests">CRIME</option>
            <option value="percapitaencampments">HOMELESSNESS</option>
            <option value="medianhoursofsummerfog">FOG</option>
            <option value="percentinliquefaction">LIQUEFACTION</option>
            </select>
        </span>
        <span class="header"> BY NEIGHBORHOOD </span>

Right now, the width of the dropdown box is set to the width of the largest item (population density). How can I make it so the width of the dropdown dynamically adjusts for each option? Specifically, when the dropdown is static and not selected.

Upvotes: 1

Views: 2582

Answers (1)

Timur  Gilauri
Timur Gilauri

Reputation: 914

First of all span - an inline element so you better use divs. It is a bad practice to put block or inline-block elements inside inline elements.

As mentioned above, it is much better to use some library for that.

Then you can use such script. Width of options calculated on initial select width and width of widest option.

findMaxLengthOpt is looking for an option with a longest text content. There is using a spread operator, that transform HTMLCollection of elements to array, so we can use Array methods such as reduce. This operator gets elements out of iterable object and put them into a new array.

Read this docs and this tutorial.

let selectList = document.querySelector("#opts")
// get initial width of select element. 
// we have to remember there is a dropdown arrow make it a little wider
let initialWidth = selectList.offsetWidth
// get text content length (not a value length) of widest option. 
let maxOptValLen = findMaxLengthOpt(selectList)
// calc width of single letter 
let letterWidth = initialWidth / maxOptValLen
let corCoef = 1.875; // Based on visual appearance
console.log(initialWidth, maxOptValLen)

selectList.addEventListener("change", e => {
  let newOptValLen = getSelected(e.target).textContent.length
  let correction = (maxOptValLen - newOptValLen) * corCoef
  let newValueWidth = (newOptValLen * letterWidth) + correction
  console.log('new width', newValueWidth, 'new option len', newOptValLen)
  e.target.style.width = newValueWidth + "px"
}, false);


function getSelected(selectEl) {
  return [...selectEl.options].find(o => o.selected)
}

function findMaxLengthOpt(selectEl) {
  return [...selectEl.options].reduce((result, o) => o.textContent.length > result ? o.textContent.length : result, 0)
}
<div class="header">
  <p>COMPARE
    <select class="select_box" id="opts">
      <option value="">Select a dataset</option>
      <option value="population">POPULATION</option>
      <option value="popdensityperacre">POPULATION DENSITY</option>
      <option value="percapitaincome">INCOME</option>
      <option value="percentnonwhite">RACIAL DIVERSITY</option>
      <option value="percentinpoverty">POVERTY</option>
      <option value="medianhomevalue">HOME VALUE</option>
      <option value="unemploymentrate">UNEMPLOYMENT</option>
      <option value="percapitacriminalarrests">CRIME</option>
      <option value="percapitaencampments">HOMELESSNESS</option>
      <option value="medianhoursofsummerfog">FOG</option>
      <option value="percentinliquefaction">LIQUEFACTION</option>
    </select>
    BY NEIGHBORHOOD </p>
</div>

Upvotes: 1

Related Questions