A few months ago I had to add a dropdown menu to a project that did not use a frontend framework with dropdown menus built in. I decided to see if I could make a dropdown menu without JavaScript. My approach is a hybrid of that found in these posts:
- https://designhooks.com/how-to-create-pure-css-dropdowns-without-javascript/
- https://css-tricks.com/solved-with-css-dropdown-menus/
Click to Open
The menu I made requires a click to open. To accomplish something similar, create a hidden checkbox with a visible label. Here, we'll use the dev.to logo for the label. When the label is clicked, the checkbox will be checked, even though it remains hidden.
This code uses the CSS general sibling combinator ~
to select the #collapse-menu
that follows the input:not(:checked)
and scale its height to 0. When the input is checked, that style no longer applies, so the scaleY
value returns to its default value of 1 and the menu appears. The transition is set to 0.3 seconds so that the menu opens gradually instead of instantly, and the transform-origin
property ensures that the menu appears from the top down instead of expanding from the center.
Hover to Open
If you prefer that your menu opens when you hover over the icon, then there is no need for <checkbox>
or <label>
tags. Instead, scale the #collapse-menu
to 0 to hide it when it is not hovered (implying that it will return to full height when hovered). You will also need to scale the #collapse-menu
to 1 when the icon is hovered. We will use the general sibling combinator ~
again to accomplish that. Last, you should introduce a delay to the transition. Otherwise when the user moves their pointer from the icon to the list, the menu will begin to collapse and then re-open. A tiny delay (0.2 seconds in this example) smooths things out.
I have intentionally kept these examples simple for ease of learning, but don't forget to think about accessibility when using these elements! Don't rely on hover behavior alone unless you're sure all of your users can use that behavior. For example, the app I mentioned earlier adds the line &:focus-within { transform: scaleY(1); }
to the CSS for the #collapse-menu
, so users navigating the site with a keyboard will see the menu expand when they tab through to one of its options.
EDIT: There are comments below complaining about the accessibility of these solutions. These issues are addressed in one of the links posted above, which I'm re-posting here: https://css-tricks.com/solved-with-css-dropdown-menus/
There is a lot more that can be done with dropdown menus in pure CSS. Add your favorite tricks in the comments!
Top comments (12)
Another accessibility problem with hover-to-open is that touch devices sometimes emulate that with a long-press but you can't rely on it.
I'm not a fan of adding spurious markup to handle something cosmetic; adding a checkbox to a page that has no semantic purpose bothers me.
I wonder why you're avoiding Javascript? Is it just an exercise or is it because you want to support users who can't (or won't) run your script? If the former, fair play, but if the latter, then why not just make the menu visible in the first place?
Thanks for the feedback! I agree about the problems with hover. That's why I used the click-to-open version.
I would argue that it has a semantic purpose. It is an element that clearly communicates its function, which is to open and close a menu. You might as well say a button has no semantic purpose.
Let's flip that around: Why would I use JS for something that is this easily accomplished in a few lines of CSS? Common JS approaches often either:
This question makes no sense to me. I wanted a dropdown menu for the same reasons everyone does, why question that choice based on how I code it?
Another issue is accessibility. Browser and e-readers doesn’t recognise this as dropdown list since it lacks of aria attributes and states
Yes, I intentionally left aria attributes off to keep the examples readable (hence my warning at the end). Can you elaborate on what you mean about states, though?
Ui component states should be defined with aria attributes.
developer.mozilla.org/en-US/docs/L...
developer.mozilla.org/en-US/docs/W...
Very cool. I like to do stuff without taking any help of JavaScript.
CSS is very powerful. Thanks for sharing this.
CSS was not made for that. Using these hacks can put you inside a tunnel of accessibilities and usability issues
Please elaborate, and please be kind. These are basic features of CSS, not hacks, but we could all stand to learn more about accessibility and usability.
Hey @equinusocio , I am just saying its very beautiful how you can create things with CSS, without using any JavaScript.
Can you tell me how it can cause issues? I would love to learn more about it!
@joshichinmay check out the CSS-Tricks link in the post. It has a long discussion about the accessibility of this approach, both in the main content and the comments.
Hey, thank you. :)
...and not the first to do it. Steve Gibson does it here for a few years now.
grc.com/menudemo.htm