How to Make a Dropdown Menu in HTML & CSS (Accessible)

Quick answer

<li class="dropdown"> <button aria-expanded="false">Services ▾</button> <ul class="dropdown-menu"> <li><a href="/design/">Design</a></li> <li><a href="/hosting/">Hosting</a></li> </ul> </li> <style> .dropdown { position: relative; } .dropdown-menu { display: none; position: absolute; top: 100%; left: 0; } .dropdown.open .dropdown-menu { display: block; } </style>

Two kinds of “dropdown”

The word means two different things in HTML, so first check which one you need:

  • A navigation dropdown: a menu item (like “Services”) that opens a list of links. You build it from lists, links and CSS. Most of this tutorial covers this kind.
  • A form dropdown: a field where the visitor picks one option, built with <select>. It’s covered at the end of this page.

Step 1: Nest a list inside a menu item

A dropdown is a list inside a list. The outer list is the main menu; one of its items contains a second <ul> with the sub-links:

  1. Start with a normal navigation menu: <nav> with a <ul> of links.
  2. Pick the item that should open a dropdown, give it a class such as dropdown, and put a second <ul> inside it after the item’s label.
  3. Fill the inner list with <li><a href> links.

Before any CSS, the sub-links simply appear indented under their parent, which is a perfectly usable fallback.

Step 2: A simple CSS hover dropdown

The quickest version uses only CSS:

  1. Give the parent item position: relative. It becomes the anchor the dropdown is positioned against.
  2. Give the inner list position: absolute; top: 100%; left: 0; so it sits right underneath, on top of the page content. Add a background and a min-width.
  3. Hide it with display: none, and show it with .dropdown:hover .dropdown-menu { display: block; }.
  4. Add :focus-within to the same rule, so it also opens when someone tabs to a link inside it with the keyboard.

Hover over “Services” in the preview.

index.html
Preview

This works with a mouse, but hover has two problems: touch screens have no hover (a tap on “Services” just follows its link), and the menu closes as soon as the pointer slips off it. Step 3 fixes both.

Step 3: An accessible click-to-open dropdown

The most reliable dropdown opens when its button is clicked or tapped, and tells assistive technology whether it’s open:

  1. Replace the parent link with a <button>. Give it aria-expanded="false" and aria-controls set to the dropdown list’s id.
  2. In CSS, show the list only when the parent has an open class.
  3. In JavaScript, toggle that class on click and update aria-expanded to true or false.
  4. Close the menu when the visitor clicks anywhere else or presses Escape.

Click “Services”, then click outside the menu or press Escape.

index.html
Preview

If the parent item should also be a page of its own (a “Services” overview page), keep a normal link for it and put a small separate button with an arrow next to it that opens the dropdown. Then a click on the text goes to the page, and the arrow opens the sub-menu.

Dropdowns inside a mobile menu

On phones, navigation usually collapses behind a ☰ button (see how to make a navigation bar). Inside that opened menu, there’s no room for a floating box, so the dropdown should open in place instead: in your mobile media query, change the dropdown from position: absolute to position: static, remove its shadow, and indent its links slightly. The sub-links then push the items below them down, like an accordion. Keep the same button and aria-expanded toggle, so one piece of JavaScript works on every screen size.

No-JavaScript option: <details> and <summary>

The <details> element opens and closes by itself when its <summary> is clicked, with no JavaScript at all, and it works with the keyboard out of the box. With a little positioning it makes a simple dropdown. The one thing it doesn’t do on its own is close when you click elsewhere on the page.

index.html
Preview

Form dropdowns with <select>

If you need a form field where the visitor chooses one option, don’t build a menu: use <select> with <option> elements. The browser draws it, it works on every device (phones show their own native picker), and its value is sent with the form. Group long lists with <optgroup>, and connect a <label> to it.

index.html
Preview

Which dropdown should I use?

ApproachWorks on touchKeyboardBest for
CSS :hoverPoorlyWith :focus-withinQuick prototypes, desktop-only sites
Button + JavaScriptYesYes, with aria-expandedSite navigation menus
<details> / <summary>YesYes, built inSimple menus without JavaScript
<select>Yes (native picker)Yes, built inChoosing a value in a form

Common dropdown mistakes

  • Hover only. Touch screen visitors can’t open it, and keyboard users can’t reach it. Use a button or add :focus-within.
  • A gap between the item and the menu. If the pointer crosses empty space on the way down, a hover menu closes. Use top: 100% with no margin.
  • Dropdown hidden behind other content. Add a z-index, and check that no parent has overflow: hidden, which clips it.
  • Menus that run off the screen. For an item near the right edge, anchor the dropdown with right: 0 instead of left: 0.
  • Too many levels. Dropdowns inside dropdowns are hard to use, especially on phones. One level is usually enough.
  • Building a fake select. For choosing a value in a form, the real <select> is more accessible than any custom menu.

Frequently asked questions

How do I make a dropdown menu in HTML?
Nest a second <ul> of links inside a menu item, give the item position: relative and the inner list position: absolute; top: 100%, hide it with display: none, and show it on hover or when a button toggles an open class.
How do I make a dropdown menu without JavaScript?
Use CSS :hover and :focus-within to show the inner list, or use the <details> and <summary> elements, which open and close on click with no script. Neither closes automatically when you click elsewhere.
Why does my dropdown menu disappear when I move the mouse?
There is usually a gap between the menu item and the dropdown, so the pointer briefly leaves the item and the :hover rule stops matching. Position the dropdown with top: 100% and no top margin.
How do I make a dropdown work on mobile?
Open it with a button click instead of hover. A few lines of JavaScript toggle an open class on the parent item and update aria-expanded, which works for taps, clicks and the keyboard.
What is the difference between a dropdown menu and a select?
A dropdown menu is navigation: a list of links that opens from a menu item. A <select> is a form field that lets the visitor choose one value, which is sent when the form is submitted.
Why is my dropdown menu hidden behind other elements?
Give the dropdown a z-index such as 10, and make sure none of its parent elements has overflow: hidden, which cuts off anything that extends outside them.