Dropdown Menu
shadcn-htmx/dropdown-menuFreeComponent
Menu of actions from a button. Native Popover API + APG menu keyboard contract (arrows, Home/End, type-to-find).
Live preview
live · rendered by the registry
Rendered by shadcn-htmx on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://shadcn-htmx.productdevbook.com/r/dropdown-menu.jsonSource
1/** @jsxImportSource hono/jsx */2import type { PropsWithChildren } from "hono/jsx"3import { cn, type ClassValue } from "@/registry/lib/cn"45// Dropdown Menu — shadcn-htmx, htmx v4 + Tailwind v4.6//7// Built on top of the native HTML Popover API (popover + popovertarget),8// so the platform gives us:9// - Light dismiss when the user clicks outside.10// - ESC closes the menu.11// - Top-layer rendering.12// - Focus restoration to the trigger after close.13//14// On top, public/site.js implements the APG menu keyboard contract:15// - ArrowDown / ArrowUp move focus between menuitems.16// - Home / End jump to first / last.17// - Type-to-find: pressing a letter focuses the next menuitem whose18// label starts with that letter.19// - Enter / Space activate the focused item.20//21// Refs:22// repos/aria-practices/content/patterns/menu-button/23// repos/mdn/files/en-us/web/accessibility/aria/reference/roles/menu_role/2425export type DropdownMenuSide = "top" | "right" | "bottom" | "left"2627type DropdownMenuProps = PropsWithChildren<{28 // Required — matches popovertarget on the trigger.29 id: string30 // Which side of the trigger the menu opens on. site.js reads data-side31 // and positions the popover via JS (CSS Anchor Positioning isn't yet32 // shipped in every browser).33 side?: DropdownMenuSide34 // role="menu" REQUIRES an accessible name. Point aria-labelledby at the35 // trigger's id (canonical menu-button wiring) or pass aria-label for36 // icon-only triggers.37 // menu_role: aria-labelledby="menubutton".38 ariaLabelledBy?: string39 ariaLabel?: string40 class?: ClassValue41}>4243export function DropdownMenu(props: DropdownMenuProps) {44 const { id, side = "bottom", ariaLabelledBy, ariaLabel, class: className, children } = props45 return (46 <div47 id={id}48 popover="auto"49 role="menu"50 aria-labelledby={ariaLabelledBy}51 aria-label={ariaLabel}52 data-slot="dropdown-menu"53 data-side={side}54 class={cn(55 "z-50 m-0 min-w-[12rem] rounded-md border bg-popover p-1 text-popover-foreground shadow-md outline-none",56 "[&:not(:popover-open)]:hidden",57 "[&:popover-open]:animate-[scn-popover-in_120ms_ease-out]",58 className,59 )}60 >61 {children}62 </div>63 )64}6566type DropdownMenuTriggerProps = PropsWithChildren<{67 menuFor: string68 class?: ClassValue69 id?: string70}>7172export function DropdownMenuTrigger(props: DropdownMenuTriggerProps) {73 return (74 <button75 id={props.id}76// … truncated
More from shadcn-htmx
All 83 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | shadcn-htmx | Components | Free | no deps | |
| Active Searchactive-search | shadcn-htmx | Components | Free | no deps | |
| Alertalert | shadcn-htmx | Components | Free | no deps | |
| Alert Dialogalert-dialog | shadcn-htmx | Components | Free | no deps | |
| Aspect Ratioaspect-ratio | shadcn-htmx | Components | Free | no deps | |
| Auto Gridauto-grid | shadcn-htmx | Components | Free | no deps | |
| Autocompleteautocomplete | shadcn-htmx | Components | Free | no deps | |
| Autosize Textareaautosize-textarea | shadcn-htmx | Components | Free | no deps |
