Jonas Fährmann

HTML <select> with dynamic size

02 April 2020

Did you ever face the problem to set the width of a <select> Element based on the selected option? Maybe this post will help you out.

The <select> Element

The HTML <select> represents a control that provides a menu of various options. In general you set the following HTML structure:

<label for="category-select">Choose a category:</label>

<select name="category" id="category-select">
    <option value="">All</option>
    <option value="books">Books</option>
    <option value="audio-books">Audio-Books</option>
    <option value="living">Living and more</option>
</select>

Normally the <select> has zero or more <option> or <optgrou> elements. The <label> in the example above is optional.

The size (width) problem

In most cases there is a problem with the width of the select Element. The normal behavior of the Element is, that it will automatically grow to the width of the largest option. Even if this one is not selected (:checked). The Designer often describes only one state of the Element with the initial option selected and a fixed width, e.g. 'All' and 80px. So if you set the width of the select to a fixed size of 80px and there is an option like 'Audio-Books' which is larger, the UI will break. As i mentioned before, the element will not change its size depending on the largest option and the text will overflow the space.

The solution

First of all i want you to keep in mind that you should try to implement components with HTML and CSS first. Only if there is no other way you can enhance your HTML/CSS with JavaScript. Well.. this solution is based on JavaScript, but only because i could not find a native one. If you have a better one without JavaScript, please contact me ;-)

See the Pen Select-Element with dynamic size by Jonas Fährmann (@jfaehrmann) on CodePen.

What is happening?

The magic: Set the width of the select Element with JavaScript based on the selected option. Easy, right? With a little trick it is easy. The trick is to set a helper element which contains the text of the :checked option. In this demo i have set up a helper Element with position: absolute and left: 9999px so that it is accessible with JavaScript but visually hidden for the user. I've also added a aria-hidden="true" to tell the browser that it should hide the element for Screen-Reader or other a11y-Tools. On every change the script will change the innerText of the helper element, gets the new offset width and updates the CSS Custom Property --dynamic-size with the new width. Furthermore there is a Custom Property arrow-size for the dropdown-arrow-width of the select element, which is added up to the dynamic sized property. That's it.