DEV Community

Cover image for CSS focus powered dropdown menu
Chris Bongers
Chris Bongers

Posted on • Originally published at daily-dev-tips.com

CSS focus powered dropdown menu

Today we'll be making something slightly different. A full CSS powered dropdown menu!

No JavaScript required!

We will make use of a button, with a focus state we'll check if we need to show this menu.

The end result will look like this:

Focus menu CSS only

For this specific tutorial, I'm using Tailwind CSS to just focus more on the actual effect.

You can find my Tailwind article here.

HTML Structure

The HTML will be a navbar container, a logo and a user icon on the right.

Tailwind does the styling, and mainly focussed on using flex to align the items.

As you can see we have a button with the ID user-menu next to it we have a div with the ID user-menu-dropdown this will be the dropdown we'll show once we focus the button.

<nav class="flex items-center justify-between h-full p-3 m-auto bg-orange-200">
  <span>My Logo</span>
  <div class="relative">
    <button id="user-menu" aria-label="User menu" aria-haspopup="true">
        <img class="w-8 h-8 rounded-full" src="https://scontent.fcpt4-1.fna.fbcdn.net/v/t1.0-1/p480x480/82455849_2533242576932502_5629407411459588096_o.jpg?_nc_cat=100&ccb=2&_nc_sid=7206a8&_nc_ohc=rGM_UBdnnA8AX_pGIdM&_nc_ht=scontent.fcpt4-1.fna&tp=6&oh=7de8686cebfc29e104c118fc3f78c7e5&oe=5FD1C3FE" />
    </button>
    <div id="user-menu-dropdown" class="absolute right-0 w-48 mt-2 origin-top-right rounded-lg shadow-lg top-10 menu-hidden">
      <div class="p-4 bg-white rounded-md shadow-xs" role="menu" aria-orientation="vertical" aria-labelledby="user-menu">
        <a href="#" class="block px-6 py-2 mb-2 font-bold rounded" role="menuitem">My profile</a>
        <a href="#" class="block px-6 py-2 font-bold rounded" role="menuitem">Logout</a>
      </div>
    </div>
  </div>
</nav>
Enter fullscreen mode Exit fullscreen mode

CSS menu on focus

To add the effect, we need to target the focus on the button.
But first, let's hide our dropdown and add a small effect.

Note: We could use @apply, but codepen doesn't support this

#user-menu ~ #user-menu-dropdown {
  transform: scaleX(0) scaleY(0);
  transition-timing-function: cubic-bezier(0.4, 0, 1, 1);
  transition-duration: 75ms;
  opacity: 0;
  top: 3.25rem;
}
Enter fullscreen mode Exit fullscreen mode

For the dropdown we add a transform to make it animate from the corner, then we add an opacity of 0 to hide it.

Now we need to target the hover.

We make use of the #user-menu:focus and then target the next (~) dropdown.

We also add a focus-within in case someone clicks a link in the dropdown, the menu will stay active then.

#user-menu ~ #user-menu-dropdown:focus-within,
#user-menu:focus ~ #user-menu-dropdown {
  transform: scaleX(1) scaleY(1);
  transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
  transition-duration: 100ms;
  opacity: 1;
}
Enter fullscreen mode Exit fullscreen mode

You can see the full example on this Codepen.

Thank you for reading, and let's connect!

Thank you for reading my blog. Feel free to subscribe to my email newsletter and connect on Facebook or Twitter

Top comments (13)

Collapse
 
angeliquejw profile image
Angelique

Given that this is a CSS-only solution, I was really anticipating accessibility to be totally non-existent. Truly grateful, Chris, to see that is NOT the case and you've thoughtfully included ARIA attributes in your example. ๐Ÿ‘๐Ÿป๐Ÿ‘๐Ÿป๐Ÿ‘๐Ÿป๐Ÿ‘๐Ÿป

Collapse
 
dailydevtips1 profile image
Chris Bongers

Thank you, Angelique, I try to do so, but it's hard.
Not 100% sure on how it would work when you tab, so it opens and how you would get it away again.

Collapse
 
yellow1912 profile image
yellow1912

On mobile clicking on the avatar again does not close the drop-down.

Collapse
 
raubaca profile image
Raul Barrera • Edited

Because it's open on avatar focus, so if you tap outside it must be closed

Collapse
 
dailydevtips1 profile image
Chris Bongers

Yeah with focus that doesn't work, you have to click anywhere BUT the avatar to close it.

Collapse
 
swizzard profile image
sam

It doesn't seem to work on ios chrome?

Collapse
 
dailydevtips1 profile image
Chris Bongers

You are right Sam!

For ios we would need to add something like this to the button:

onclick="this.focus()"
Enter fullscreen mode Exit fullscreen mode

But then we are using JS again, and it won't re-close the menu with this.

Collapse
 
swizzard profile image
sam

well that's a bummer--there's no shim or any other option?

Thread Thread
 
dailydevtips1 profile image
Chris Bongers

Hey Sam, unfurtionally not that I know off, someone else might know, I'll do some more research on how to fix this for iOS stable.

Collapse
 
rahxuls profile image
Rahul

Amazing post for beginners and everyone. Usually, when doing this i made mistakes but all is clear now. Amazing๐Ÿ’ฅ๐Ÿ’ฅ๐Ÿ’ฅ

Collapse
 
dailydevtips1 profile image
Chris Bongers

Oh very nice to hear Rahul, glad it's clear

Collapse
 
raubaca profile image
Raul Barrera

Nice tip!

Collapse
 
dailydevtips1 profile image
Chris Bongers

Thank you Raul! โœŒ๏ธ