"Dropdown" is four different components wearing one word, and picking the wrong one is the most common cause of a form field that fights its user. A menu of actions, a picker for one value out of a known list, a searchable picker for one out of hundreds, and a navigation panel are four separate problems with four separate keyboard contracts.
54 public components on 21st have "dropdown" in the name and 95 more say "select". Sorting them by contract rather than by look is the whole job.
Menu: a list of things to do
Actions, not values. Edit, duplicate, delete. It opens on click, it closes when something is chosen, and nothing about it is remembered afterwards.
User Dropdown by Ayman Echakar and Profile Dropdown by kokonutd are the account-menu shape every app has in its top-right corner. Dropdowm Menu by Chetan Verma and Material UI Dropdown Menu by Hossain Jahed are the general versions, and Fluid Dropdown by Kousthubha Yadiyala is the animated take.
The contract: arrows move between items, Escape closes and returns focus to the trigger, typing a letter jumps to the item starting with it, and the trigger carries aria-haspopup with aria-expanded. A menu item is not a link and not a checkbox unless you say so with a role.
Select: one value from a short list
A value the form will submit. Country, plan, status. It must be labelled, it must show what is currently chosen, and it has to survive being reset.
The uncomfortable truth here: on a phone, the native <select> is better than almost every custom one. It opens the platform picker, it is one tap, it works with the on-screen keyboard, and it never renders behind something. Style the closed state and let the platform own the open state unless you have a reason not to.
Reach for a custom select when you need option groups with real structure, icons or avatars beside options, or multi-select with visible chips. Those are genuine reasons. "It looks different on Windows" is not.
Combobox: one value from a list too long to scroll
The moment a list passes roughly twenty options, browsing stops working and searching starts. That is a different component: a text input with a filtered listbox under it.
The contract is the strictest of the four. The input keeps focus while arrows move a highlight through the list, aria-activedescendant tells assistive technology which option is active, Enter commits, Escape reverts, and the filtered result count is announced. This is where hand-built implementations break, and where taking the behaviour from a library is the correct instinct.




Navigation menu: a panel, not a list
The fourth case, and the one with the most different rules. Navigation menu by shadcn is the primitive; Navbar with Dropdowns from Shadcnblocks.com and Navigation Menu by Efferd are assembled headers; Mega Menu by LN is the wide multi-column panel; Shifting Dropdown by Hurera Sheikh animates the panel between triggers.
Three rules that are specific to navigation and get broken constantly. Hover-to-open must also work on click and on Enter, or the menu does not exist for keyboards or touch. A hover intent delay of 100 to 200ms prevents panels flashing as the pointer crosses the bar. And the panel's links are real links: a mega menu built from click handlers is invisible to every crawler, which matters because the header is the most-linked block on a site.




The three bugs every dropdown has
It is clipped by an ancestor. A panel inside a container with overflow: hidden or a transformed parent gets cut off. The fix is a portal to the body, which every serious primitive does by default and every hand-rolled absolute-positioned panel does not.
It flips off the screen. Near the bottom or the right edge, a fixed-direction panel opens into the void. Collision-aware positioning belongs to a library like Floating UI, which is what most primitives use underneath.
It closes when you scroll, or does not. Inside a scroll container the panel drifts away from its trigger unless it is repositioned. Decide deliberately: reposition, or close on scroll. Doing neither is what produces a floating panel over unrelated content.
And one that is not a bug but reads like one: a dropdown that opens on hover and closes the instant the pointer leaves has no forgiveness. Give it a small close delay, or a safe triangle between the trigger and the panel, or every diagonal mouse path loses the menu.
Where else to look
The honest list of alternatives, because the answer is not always us:
| Source | Best for | Trade-off |
|---|---|---|
| shadcn/ui | DropdownMenu, Select, Combobox and NavigationMenu as four separate things | Plain by design; the panel styling is yours |
| Radix / Base UI | The behaviour underneath: portals, collisions, typeahead, focus | Unstyled, and four primitives to learn |
| Floating UI | Positioning alone: flip, shift, arrow, collision detection | Not a menu, just where to put one |
| cmdk | Command palettes and search-first pickers | A different interaction from a select |
| 21st | Finished profile menus, mega menus and animated panels | Quality varies by author, so preview before you take it |
Taking one
Every component page has a live preview and the code. Installing goes through the shadcn CLI against our registry:
That key comes from your 21st account, and installs require a membership. Set API_KEY_21ST once in your shell and the command works for anything in the catalogue. The 21st MCP covers the same ground without leaving the editor: ask Claude, Cursor or Codex for a dropdown, get the previews inline, and let the agent write the file.
Frequently asked
- What is the difference between a dropdown menu and a select?
- A menu holds actions and remembers nothing; a select holds a value the form will submit. They have different keyboard contracts and different ARIA roles, and using a menu where a select belongs is why some forms cannot be filled in with a keyboard. A combobox is the third case: one value out of a list too long to browse, so it needs a text input and filtering.
- Should I use a native select on mobile?
- Usually yes. The native select opens the platform picker, works with the on-screen keyboard in one tap, and never renders behind something. Style the closed state and let the platform own the open state. Build a custom one when you genuinely need option groups, avatars beside options, or multi-select with visible chips.
- Why is my dropdown cut off or positioned wrong?
- Two causes. An ancestor with overflow: hidden or a transform clips the panel, which a portal to the body fixes and which every serious primitive does by default. And near a viewport edge a fixed-direction panel opens off-screen, which needs collision-aware positioning of the kind Floating UI provides and most hand-rolled absolute panels do not.
- How do you make a hover menu work on touch and keyboard?
- Make hover an enhancement, not the mechanism. The trigger must also open on click and on Enter, with aria-expanded reflecting the state. Add 100 to 200 milliseconds of hover intent so panels do not flash as the pointer crosses the bar, and give a close delay or a safe triangle so a diagonal mouse path does not lose the menu.