The DOM Diet and Year Pickers

I think we all know that having a smaller DOM is good for performance but I was never sure what’s considered big or small, or at what points performance is affected. Knowing a little more can change how you approach things.

I was recently doing a performance analysis on some pages and the tool I chose to use was the Chrome Performance Audit. If you open Dev Tools (F12) and go to the Audits tab you’ll see a range of available audits which includes Performance. This uses a tool called Lighthouse and gives estimates for various performance metrics as well as Opportunities and Diagnostics.

One of the diagnostics which came up for me was “Uses an excessive DOM size” and the detail gives us this:

Browser engineers recommend pages contain fewer than ~1,500 DOM nodes. The sweet spot is a tree depth < 32 elements and fewer than 60 children/parent element. A large DOM can increase memory usage, cause longer style calculations, and produce costly layout reflows.

The item that triggered this diagnostic for me was a year picker, a select element with 150 options. Whilst I don’t think it’s really causing any major performance issues it did strike me that 1 parent element and 150 children does seem excessive for just picking out one number from a consecutive range so I started looking at alternative ways we could do this. I wanted to put my year picker on a  “DOM Diet”. I created this pen:

See the Pen Year Pickers by Chris Smith (@chris22smith) on CodePen.dark

Here’s a quick comparison of 4 possible ways of selecting a year from a consecutive range. It’s important to not only look at possible DOM performance but also the user experience side – ease of understanding and ease of use. No point making it faster if it’s confusing or hard work.


This is the standard method. It can have a default value or a blank value as the first option. It’s very familiar, ease to understand and use. It’s probably better to start with a blank value so that we know a user has actually made a selection rather than just left the default. It supports arrow keys and mousewheel. It’s easy to validate using just the required property as the available options are set. It can look untidy in some browsers when long option lists run off the bottom of the screen and it does use a lot of DOM nodes.

Range Input

The input[type=range] doesn’t show a value by default so you have to do a bit of work to show an output value, and a bit more work to do this elegantly. Through testing I found the output value had to go above the slider rather than below so it was not obscured by a finger using the control. I think this is fairly easy to understand but users may not be aware that they can use their arrow keys to get greater precision – either up/down or left/right. It can be hard to control and get the exact figure you want dragging the handle especially using a finger. It can also be wired up to support the wheel event and respond to scrolling up or down on the mousewheel. There’s no way to have a blank value so it has to have a default set. There’s no real validation to be done as it has to use a value in the range. It’s very kind to the DOM too with only 3 nodes.

Number Input

This method is very simple. You just let the user type in the date they want. It can be left blank or have a default value. It can be controlled using arrow keys or the mousewheel though I’m not sure how many users know this. By setting the min, max and step attributes it can limit the range entered when not typing. If the value is typed (or pasted) it will require validation. This uses a single DOM node.

Multiple Number Inputs

This final method is just a bit of a “left field” design. The advantage of it is that it’s very easy to update using the tab key and arrow keys. By having the digits separated the range for each is only ever 10 so in theory it should mean less to change. If left blank it could be set to automatically shift the focus to the next input when a value is added. This makes it as fast to type the 4 digits as a single number input. The min, max and step attributes can limit the range for each digit. It’s light on the DOM too with only 5 nodes. The disadvantage with this method is the validation – it’s going to be a bit more involved, parsing the 4 digits as a single value to be checked and then highlighting the invalid digit(s) could be difficult. On a mobile device with a number pad it also means the pad flashing in and out quickly, which is not a great experience so it’s only really suitable for desktop use.

I’m not sure I’d necessarily go running from the standard dropdown but some of the other methods are certainly possibilities and help keep the DOM smaller.

Native Browser Controls Rule

It’s become very common for designers to replace the standard native browser controls with their own custom controls. There are good reasons for this, consistent appearance across browsers and devices being the main one. However, there’s a lot more to consider than just how it looks.

Form Controls

Let’s think about something like a slider switch in place of a good old fashioned checkbox. It looks cool but…

Is it accessible?
How does it appear to a non screen user?

Does it have a disabled state?
And a read-only state?
And a focus state?
Do these states all also work for non visual users?

Can you tab to it?

Does it go back to its initial state using a form reset?

Does it work with touch gestures, e.g. swipe left to right?


Now let’s think about a simple link. It’s pretty common to see icons used with an onclick event instead of links. But its not the same.

How would a user know that it’s an interactive control? Maybe it has a hover state style change but this would not help a non screen user.

A link (a tag with href attribute) does other things. You can tab to it. On Windows, you can use Ctrl + click to open in a new tab, Shift + click to open in a new window, right click and “Save link as…” (or equivalent) to download the target file. Wrapping the icon in an tag opens up a lot more possibilities.

I’m not saying don’t use your own controls but before replacing native controls think about what you might be sacrificing and make sure you’ve got it all covered.

Displaying Options in a UI

One of my pet hates in UIs is seeing a drop down list (select tag) in a form with only a single option in it. As a user you have to click it to see the other available options only to find that there are none. This is a clear example of developer convenience being put before user experience.

I’m sure it seems obvious now I’ve highlighted it but if there’s only one option then there isn’t a choice to be made at all and we don’t need a form input. The code should conditionally show the drop down list only when there is a selection to be made, more than one item.

Depending on the UI design, we could even take this a step further. Maybe a drop down list isn’t the best choice for selecting between 2 items? A radio button list is probably better as it enables the user to see all of the available options at a glance and make a selection with a single click/touch. We can test the number of options and if it’s below 5 show the options in a radio button list. <ol> might be a better choice than <ul> for the list if the items are in a specific order, e.g. years.

Another example I see is displaying disabled form controls where the control is never enabled, e.g. a checkbox which is disabled because the user doesn’t have permissions to change it. If it’s not an option, don’t show it. Disabling it is the lazy option, easy for the developer. Hiding it is much better but may involve a change to layout. The UX should always be put first. It’s usually no more difficult, it’s just not considered.