Create a Discreet "Dropdown" Menu

The select Element

The select element is mainly associated with drop-down menus/lists. That's the default after all. You add a select element to a page and you see a white rectangle with an arrow pointing down at one end. You click on it, and based on the default behaviour you see a drop-down list of options for you to choose from.

This is the default behaviour on desktop browsers (and tablets?), but have you ever tabbed on a select element on a mobile browser? There are 2 behaviours I've seen:

  1. Options displayed in a popup at the bottom of the screen (where the keyboard pops up)
  2. Options displayed in a popup at the centre of the screen

On mobile browsers, users see a list of options but not in a drop-down list. Tabbing the select element when styled using its default styling (white rectangle with an arrow pointing down) doesn't trigger the expected behaviour based on its visual representation. The user doesn't get a drop-down list.

Besides, the W3C's definition of the select element doesn't explicitly describe it as a drop-down list.

"The select element represents a control for selecting amongst a set of options."

So styling the select element differently may make sense in some situations. Here's a semantically correct, pure CSS method to do just that.

What we will do

  • Remove the default styling of the select element (including the arrow)
  • Position the label to overlap the select element and make it look clickable without affecting functionality or semantics (in reality the user will be clicking the select element not the label)
1<div id="wrapper">
2 <label for="select-options">Change</label>
3 <select id="select-options">
4 <option>Option 1</option>
5 <option>Option 2</option>
6 <option>Option 3</option>
7 </select>
8</div>

All you need is an explicit label and the select element itself (just like you would normally create it).

We need to edit the styling of their parent element. If your markup allows you to apply the below styles without affecting your page's layout, do so. Otherwise, you may need to add a div wrapper.

Now we have an explicit text label using the label element. And we have set the value of the for attribute on the label element to match the value of the id attribute on the select element. This is semantically correct and there shouldn't be accessibility concerns.

Parent Element

1.wrapper {
2 position: relative;
3 width: 300px;
4}

For the parent element, in this case our div wrapper, we set the position property to relative because we will be applying absolute positioning for the label. The width can be whatever suits your layout.

select Element

1select {
2 /* remove default styles */
3 background: transparent;
4 border: none;
5 -webkit-appearance: none;
6 -moz-appearance: none;
7 appearance: none;
8 
9 /* keep on top so it's clickable */
10 position: relative;
11 z-index: 99;
12 cursor: pointer;
13 
14 /* padding-right to prevent text overlap with label */
15 /* padding-bottom to assist with :focus styling */
16 width: 100%;
17 padding: 7px 70px 7px 0;
18 
19 /* some browsers support text wrap in select element */
20 white-space: normal;
21 font-size: 1em;
22 line-height: 1.35;
23}

Here we remove the default styles of the select element. Setting the appearance property to none is what removes the arrow.

Because we will be absolute positioning the label in an overlapping manner, we have to increase the z-index of the select element to make sure the user can interact with it. Setting the cursor to pointer makes it more user friendly on desktop browsers.

Adding some padding-right will prevent the text of the select element from overlapping with the label. The padding-bottom is needed for the styling of select:focus.

Setting white-space to normal will make the text of the select element wrap to another line if it's too long (doesn't work in all browsers).

Label

1label {
2 position: absolute;
3 top: 50%;
4 right: 0;
5 transform: translateY(-50%);
6 font-size: 0.8em;
7}
8 
9.wrapper:hover label {
10 color: #6feaa2;
11}

We vertically centre the label and position it to the right of the parent element.

The aim is to make the user think they can click/tab on the label to select another option, but in reality they are clicking on the select element. So you may want to style it to look like a button.

Note if you want to change the position of the label, just make sure the select element covers the new position (adjust height, width or padding).

Accessible & Tidy

By default browsers add an outline to focusable elements such as links and some input elements because of accessibility reasons. The outline provides a visual cue for users who are visually impaired or users who are unable to use a mouse. These users often rely on using the Tab key or assistive technologies to navigate through a page.

Leaving the outline for the select element here causes a problem: when it is clicked or in focus the outline overlaps with the label and it looks a bit messy. Removing it also causes a problem: it makes the page less accessible for some users.

Alternative :focus Styling

1select:focus {
2 outline: none;
3 border-bottom: 2px solid #8eb0e7;
4 /* decrease padding-bottom by border-bottom-width */
5 /* This prevents it from affecting the layout */
6 padding-bottom: 5px;
7}

So here we're defining a custom visual cue for this group of users. It's just a border-bottom, but should do the trick (choose the colour carefully).

Uses & Limitations

The first possible use case is what I discussed at the very start: for mobile devices. You could easily reset the defaults for wider viewports.

Another possible use case is if you want to use the select element not only to provide a control for selecting an option, but also to display the selected option as information. I’ve used it in an audio visualisation experiment in which I made it possible for the user to change the streaming track via a select element. I didn’t want to have a select element where the track title is visible and display the track title some where else as well.

There are some limitations though. Given that not all browsers support text wrap in the select element means the options have to be short to use this method. And since the select element and the label have to overlap, the label text needs to be short as well (unless you position it above or below the select element and increase the select element's height or padding).

I have not done any user testing. I have no idea whether this method will generate any confusion to some users. On the other hand, most users are already familiar with the default styling of the select element, so when they see it they know there are options to choose from straight away.

Your choice of the label text has to be made carefully. Using verbs like 'change' or 'choose' will make it clearer to the user that there is some interaction required.

Browser Support

This solution relies on setting the appearance property value to none which is supported in most browsers with vendor prefixes. IE desktop doesn't support it all, but surprisingly IE Mobile 11 does!

Check browser support