Building a Custom Select field without any JavaScript

Imagine the following scenario: You, a website developer, are given an interesting design for a website to develop. While feature-rich, you notice the forms used contain custom designed select fields. Most form fields are globally known in the web development field for not adhering fully to style rules, likely due to their development made to conform to native design. As such, a dropdown arrow will look different in each Operating System. No biggie! Just whip up a custom component which looks like a dropdown field, place it on top of the select tag, ensuring it is hidden, and bind functions to open it when the custom component’s arrow is clicked. Easy!

While the above is an excellent solution, and there are several examples online explaining how to render this custom field, depending on the usage of your dropdown list by users and devices, it may likely not be needed as the display of its items (the option tags) may be better appreciated in a mobile setting, in which native display may override any given style, all in the name of facilitating the user to perform a selection.

The Problem

How would it be possible to simplify the display of a custom dropdown list, without depending on many extra tags and any JavaScript functions?

The Proposal

If we are to take a page from what website builders that bloat a page’s code for the sake of added functionality, we could assume in a thought exercise each DOM element is draggable and able to be positioned anywhere on the screen without breaking layout. As such, it could be understandably easy to create one, if we’re able to position the elements (the dropdown, and the arrow) we want to style on top of each other, much in the way that happens with custom select fields.

The Solution

Thanks to newer versions of CSS, this is actually possible. For one, an element’s position in the DOM can be easily modified thanks to the position property. As long as we have an absolute element, either inside the page body or a parent element whose position is relative, we are able to modify its position to place it anywhere we want.

Even without positioning, it is also possible to modify the position of an element thanks to the transform property. This allows us to move an element from its position horizontally, vertically, or both, by specifying arguments of translation which may be measured units (like pixels), percentage units, or viewport units.

Last but not least comes the inevitable realization. “Hey, genius! If you put an element on top of another how are you gonna activate the dropdown if you click on the arrow? You need JavaScript for that!” This is true. But, once again, modern CSS comes to the rescue. A property which handles pointer events, namely the one called pointer-events, allows us to assign it an element, which will allow for any mouse events on it to “pass through” so that any element rendered below it experiences it.

The Implementation

To make the picture above a reality, we need code for both HTML and CSS. In HTML, the idea will be to use as few elements as possible in order to render the dropdown:

Before I explain the HTML, let’s see the CSS:

So now that both are available, I’ll explain:

  • Although not necessary, a container, noted by the div with idselect-container, is placed, as a wrapper for the dropdown and arrow image. It is written as an added security to ensure absolute elements do not escape the boundaries of the dropdown list. Note how in CSS it has a relative position.
  • The select tag, noted by id dropdown, will encompass the width and height given to its parent, the container, as well as some styling to change its font color, background color, border color and radius, and padding. The property outline is also specified and set to none so that if the list is clicked, the outline provided by the browser doesn’t surround the element without accounting for the border radius:

The select tag also has a cursor property, but I’ll discuss that one later.

  • The options, or list elements, have been placed here for purposes of the example, and thus do not limit this technique in any way.
  • Lastly I have included an image which has all of the styling of the arrow from the “design”, included in it, but it’s possible to render your own arrow fully with CSS, as I only included it here for simplicity.

The Trick

Note how the properties specified are being used! Because the container has a relative position and the image has an absolute position, any change in position made to the arrow image will restrain it to the coordinates of the container. The transform property is then used, to move the arrow image its whole width to the left, thereby placing it on the right edge of the select tag, right on top of the unruly arrow. pointer-events: none works like a charm then to let the select arrow receive the clicks. With all the code provided, we should be able to get a custom dropdown list like this:

Also note that, while it may be possible to get this by using display: flex on the container, thereby removing both position attributes, the select element will adjust to 100% of the container’s width, minus the width given to the arrow image, but the idea is to have a dropdown list whose width matches the one of the container.

The Drawbacks

Sadly, because this is a trick that depends on the use of a native HTML element, it is not possible to edit the option elements’ width. So this custom dropdown will not look as pretty if your custom element has rounded corners:

Also, because there are no pointer events for the arrow image, nothing happens to the mouse pointer as it enters the arrow image. This is why the select tag has a cursor: pointer property, to simulate recognition of the mouse over the image. This is no native behavior, but it provides some form of interactivity in a desktop environment.

But, if you’re targeting a mobile audience, then native list selection should take over, and the regular desktop option items would not be visible, nor would there be a need for cursor changes.

Conclusion

Although it will always be better to understand the functionality of a custom-made dropdown list, having the alternative to create a decent looking one with the tools natively provided never hurts.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store