GitHub

Dropdown Menu

A compact action menu for contextual commands, toggles, and grouped options.

DropdownMenu presents focused actions near a trigger without taking over the page. It is built on Radix UI, so it preserves expected menu semantics, roving focus, dismissal behavior, and keyboard navigation while matching the glass styling used across the component set.

Use it for contextual actions, lightweight settings, and small grouped choices. If the content needs long-form input or larger layouts, use a bigger surface instead.

Installation

npx @glass-ui-kit/cli add dropdown-menu

Usage

import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import { Button } from "@/components/ui/button"
export default function App() {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="strong">Workspace</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem>Rename</DropdownMenuItem>
<DropdownMenuItem>Duplicate</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}

Examples

Variants

Use the variant prop on DropdownMenuContent to tune the floating surface depth without changing the trigger.

Selection controls

Use checkbox and radio items when the menu needs to toggle visibility or switch between compact option sets.

Controlled

Use open and onOpenChange when another part of the interface needs to coordinate the menu state.

import { useState } from "react"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
import { Button } from "@/components/ui/button"
export default function ControlledDropdownMenu() {
const [open, setOpen] = useState(false)
return (
<DropdownMenu open={open} onOpenChange={setOpen}>
<DropdownMenuTrigger asChild>
<Button>Project actions</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem>Open details</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}

asChild

Use asChild on DropdownMenuTrigger when another interactive element should own the visible trigger. In that mode, Radix forwards menu state and ARIA props to your child, and your child owns the final layout and styling.

import { Button } from "@/components/ui/button"
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
export default function CustomTriggerDropdownMenu() {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="strong" className="min-w-32 justify-between">
Workspace
<span aria-hidden="true"></span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem>Rename</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}

Styling

Dropdown Menu keeps the API small. Reach for variant on DropdownMenuContent first, then use Radix placement props such as side, align, and sideOffset for layout tuning. Use className as an escape hatch for local width or spacing adjustments.

/* Content variants */
<DropdownMenuContent variant="default" />
<DropdownMenuContent variant="soft" />
<DropdownMenuContent variant="strong" />
/* Placement */
<DropdownMenuContent side="right" align="start" sideOffset={8} />
/* Controlled state */
<DropdownMenu open={open} onOpenChange={setOpen} />
/* Escape hatch */
<DropdownMenuContent className="w-64" />

API Reference

Accepts all Radix DropdownMenu.Root props.

PropType
defaultOpenboolean
openboolean
onOpenChange(open: boolean) => void
modalboolean

Accepts all Radix DropdownMenu.Trigger props.

PropType
asChildboolean
disabledboolean
classNamestring
PropType
variant"default" | "soft" | "strong"
side"top" | "right" | "bottom" | "left"
align"start" | "center" | "end"
sideOffsetnumber
collisionPaddingnumber | Partial<Record<"top" | "right" | "bottom" | "left", number>>
loopboolean
classNamestring

DropdownMenuContent defaults to align="start", sideOffset={8}, and collisionPadding={8} so action lists stay close to the trigger without crowding the viewport edge.

PropType
disabledboolean
onSelect(event: Event) => void
classNamestring
PropType
checkedboolean | "indeterminate"
onCheckedChange(checked: boolean) => void
disabledboolean
classNamestring
PropType
valuestring
onValueChange(value: string) => void
disabledboolean
classNamestring

Use these when a compact secondary action group should stay nested in the same contextual menu. DropdownMenuSubContent accepts the same variant, placement, and className escape hatches as DropdownMenuContent.

Use these helpers to group commands, separate sections, and align compact keyboard hints without adding more layout wrappers.