Custom <select> drop downs with CSS3

The CSS3 Basic UI module defines pointer-events as:

The pointer-events property allows authors to control whether or when an element may be the target of user pointing device (pointer, e.g. mouse) events. This property is used to specify under which circumstance (if any) a pointer event should go “through” an element and target whatever is “underneath” that element instead. This also applies to other “hit testing” behaviors such as dynamic pseudo-classes (:hover, :active, :focus), hyperlinks, and Document.elementFromPoint().

The property was originally SVG-only, but eventually browsers and the W3C adopted a more limited version for HTML elements too.

It can be used in many use cases that weren’t possible before (or the solution was overly complicated), one of them being to create custom-looking <select> drop downs, by overlaying an element over the native drop down arrow (to create the custom one) and disallowing pointer events on it. Here’s a quick example:

-webkit-appearance: none was needed in Webkit to turn off the native OSX appearance (in OSX and maybe Safari on Windows, I didn’t test that). However, since that also removes the native drop down arrow, our custom arrow now obscures part of the text, so we had to add a 30px padding-right to the select element, only in Webkit.

You can easily detect if pointer-events is supported via JS and only apply this it if it is (eg by adding or removing a class from the body element):

if(!('pointerEvents' in document.body.style)) {
    ...
}

However, there is one caveat in this: Opera does include pointerEvents in HTML elements as well, but it does not actually support the property on HTML. There’s a more elaborate feature detection script here as a Modernizr plugin (but the code is quite short, so you can adapt it to your needs).

Also, don’t try to replicate the behavior in JavaScript for browsers that don’t support this: it’s impossible to open a <select> drop down with JavaScript. Or, to put it differently, if you manage to do it, you’ll probably be the first to. Everything I could think of failed and I spent hours yesterday searching for a way, but no avail.

References

  • http://phaistonian.pblogs.gr George Papadakis

    -webkit-appearance: button would actually do the trick.

    Can’t see why you need pointer-events on this one.

    Well said though:)

    • http://leaverou.me Lea Verou

      Firstly, because there are other browsers besides Webkit based ones, in case you haven’t heard :)

      Secondly, did you actually try your suggestion? It doesn’t work (and I don’t see why it would, since the custom arrow will capture the mouse events itself if pointer-events is set to auto (the default) no matter what appearance value it has).

      • http://phaistonian.pblogs.gr George Papadakis

        Try chrome://settings/browser on Chrome.

        Then view-source. Inspect the .

        And yeah, I thought this was about Webkit – Too much Chroming does that – my bad :)

        • http://leaverou.me Lea Verou

          Yeah, buttons have a default appearance of button and select elements a default appearance of menulist in Chrome, but I don’t see how this is relevant. Am I missing something?

        • Giancarlosaquilayan

          nice!

  • Anonymous

    A bit off-topic, but we’re having terrible problems with pointer-events: none; applied to SVGs in Chrome, where an SVG layer on top of some HTML does not let pointer events through. We filed a bug and a fix about a year ago and yet it’s still broken. The short of it is: I don’t fully trust pointer-events: none; yet.

    • http://leaverou.me Lea Verou

      My experience with SVG is fairly limited. The only times I used pointer-events was with HTML, so I haven’t ran into this issue yet. Sounds horrible. Yeah, Webkit has a reputation of not fixing their bugs quickly. There’s this horrible bug with sibling selectors and pseudo-classes not being applied that’s been lingering in Webkit for at least 3 years for example.

    • http://twitter.com/kartiksehgal kartik sehgal

      Why don’t you try a jQuery plugin like jALDropdown? india.assigninfo.com/assignlabs

      • http://leaverou.me Lea Verou

        Because recreating selects with JavaScript always has usability and accessibility issues, less or more. And you’re kinda missing the point of this post (and of my whole blog actually).

  • Benoit

    it’s impossible to open a drop down with JavaScript: have you tried programmatically dispatching a click event on it?

    • http://leaverou.me Lea Verou

      Of course.

  • Anonymous

    Thanks

  • Weppe

    Is it possible to do something like that to radio button?

  • Fooo

    You are abusing feature detection for unrelated, accidental browser behaviour. Please stop.

    • http://leaverou.me Lea Verou

      You are trolling anonymously, without even explaining wtf you’re complaining about. Please stop.

  • Fooo

    You are abusing feature detection for unrelated, accidental browser behaviour. Please stop.

  • Fooo

    You are abusing feature detection for unrelated, accidental browser behaviour. Please stop.

  • http://profiles.google.com/jswartwood Jacob Swartwood

    Excellent work! My biggest frown is about the position: relative… I’ll see if I can tweak this at all to put the :after on select and still have something working.

  • Alex Dearden

    This is great, nice job. I do have one question though,  I can’t get the arrow to show up when I adapted my selects based on yours. The arrow code I copied verbatim. Is there some magic to make it show up? 

    Thanks. 

    • http://leaverou.me Lea Verou

      No magic required :)

      I would assume that you’re either using a browser that doesn’t support pointer-events on HTML elements, or you missed something from the code. Is there any uploaded example I can check?

      • Kakubei

        well it should support it since I see your example fine. I’m using Chrome on OS X.

        I put up a test page here:

        http://bruji.com/triangleTest.html

        I had to copy paste a bunch of stuff from the css file so please excuse the ugliness of the page. The CSS are in the head of the document.

        I’ve tried commenting stuff out, on the :after declaration, etc but I just can’t get any output from it.

        Thanks for looking!

        • http://leaverou.me Lea Verou

          You don’t have a wrapper label, which is needed, since the :after pseudo-element is on it (replaced elements can not have generated content). Labels are also needed for accessibility, so you should really have one anyway.

        • Kakubei

          Wow, I would have never thought it was that! Thanks a lot.

          Interestingly, I can see the triangle with Safari, but not Chrome, yet I can see your example with either browser… no doubt there is still something weird in mine.

          Also, if I may try your patience with one last thing: is it possible to create a button like the one at the bottom of this page just with CSS? Can you create a circle in CSS like the one holding the triangle?

          http://bruji.com/triangleTest.html

          Thanks again.

  • Daniel

    great find!

  • Mahesh Awati

    This is gr888 help! Thanks a ton.

  • http://twitter.com/chalassa Diego Oliveira

    Nice idea!

    When i click at “after” pseudo-element the IE9 don’t recognize that click and nothing happens.
    Because IE9 don’t support pointer events and your test returns a wrong value for IE9, any solutions?

    Thanks!

    • http://leaverou.me Lea Verou

      Not really. It’s an experimental method, and there’s no feature detection technique for pointer-events so far.

      • ausi

        i tried to write a feature detection for pointer-events:
        https://github.com/ausi/Feature-detection-technique-for-pointer-events

        it works correctly in all my browsers. (test page: http://ausi.github.com/Feature-detection-technique-for-pointer-events/)
        maybe you can use this script…

        • http://leaverou.me Lea Verou

          Brilliant! Post updated!

        • http://twitter.com/rwlinda Linda Stuurman

          IE9 still doesn’t work for me … using ausi’s script. Anyone able to get IE9 to work properly? Thanks!

        • ausi

          how did you use my script?
          it should detect correctly that ie9 does not support pointer-events.
          if the detection works correctly and says pointer-events are not supported, you have to hide the custom arrow element.

        • http://twitter.com/rwlinda Linda Stuurman

          Here’s a link to where I used it: http://www.robin-williams.net/test/test.html

          It does say pointer-events not supported, but by hiding the custom arrow element I get the default arrow back in return. 
          Thanks for your reply.

        • http://leaverou.me Lea Verou

          Yes, there is no way to use this technique in IE9. My suggested fallback was to detect pointer-events support and fall back to the default <select> menu in browsers that don’t support it. :)

          Good luck and thanks for the nice words about my talk!

        • kaye

          hi Linda,
          i know that this is way too long ago but i have the same problem with yours, it seems that it worked in your project. would you care to share how you use the plugin? im kind of having difficulty understanding on where to put the plugin. thank you.

        • Linda Stuurman

          Hi. I did a redesign earlier this year and rewrote the css and js. I do not have this plugin included in the current site…

  • http://twitter.com/rwlinda Linda Stuurman

    Sorry, questions answered … I think … will try and find the solution myself. Sorry about this post

  • Ferenc Szabo

    “Opera does include pointers events in HTML elements as well, But Actually it does not support the property on HTML” pobléma to correct a temporary solution:*******************************************************************************************var closed = true;function Select_Size(select_obj, select_name, option_number){ if (navigator.appName === ‘Opera’)  { var frm=select_obj.form;    var select_aktual=frm[select_name];    if (closed)    {closed = false;  select_aktual.size=option_number;  }    else    {closed = true;   select_aktual.size=1;   }  }}//HTML  *******************************************************************************************
    DEMO: http://family-team.emszinet.hu/proghutest/10/cssgradient/cssgradient.html

  • http://jitendravyas.com/ Jitendra Vyas

    I could use this in a project but it’s not working if user click on arrow image in IE. But it’s really best custom dropdown without Javascript

  • Eric

    thank you so much! it’s so helpful!

  • Pingback: How to style a <select> dropdown with CSS only without JavaScript? | Everyday I'm coding

  • Pingback: Making HTML dropdowns not suck - RedTeamDesign

  • Sanjay Kandgal

    Hi Lea,
    Thank you so much for great fix….
    But in IE 10 version. selection option is not working when you click on Arrow mark…
    it will work on only clicking on the content…

  • João Cunha

    Hi, Lea!

    I’ve just figured out how to enforce “-moz-appearance: none” on Firefox in order for it to ditch the select arrow (like Chrome and Safari do). This is how to do it:

    https://gist.github.com/joaocunha/6273016

  • Guest

    Hi, Lea!

    I’ve just figured out how to enforce “-moz-appearance: none” on Firefox in order for it to ditch the arrow (like Chrome and Safari do). This is how to do it:

    https://gist.github.com/joaocunha/6273016

  • Pingback: Customizing Select Menus: To the future and beyond | Gray Ghost Visuals Press

  • Pingback: How to add style on form select element only with CSS | Tim Yao

  • jitendra sahoo

    thank you so much! it’s so helpful!
    http://www.themebox.in/tutorials

  • Swapnil

    Awesome it saved my life, Thanks Lea

  • ImLeTired

    Great dropdown style! I am having trouble setting the width in % however, the triangle gets a little lost.

  • kaye

    Hi Lea,

    Thanks for sharing this, it has been years since it is posted but still helps others like me. Im newbie to web dev and Im kind having problem on the issue on IE10. Can you please teach me on how to use the plugin and the jquery script to handle the problem in IE10? Im kind of having difficulty understanding on where to put these codes. thank you.

  • Pingback: How to: How to style a <select> dropdown with CSS only without JavaScript? | SevenNet