Components/Dropdown Menu

Dropdown Menu

Thirty-two variants across six components: twenty-two rows, four menus, a submenu trigger, the trigger button, a heading and a rule.

DropdownMenu / Item · Components frameLive in the browser · drawn to match the file
Variant
State
Show Icon
Dropdown Menu Item Text ⇧⌘P
Variant=Shortcut · State=Default · Show Icon=Yes312 × 28 in the file
two hovers, two surfaces

Hover is a solid base.muted; Hover (Translucent) is the same fill at 70%, so a frosted panel still shows through the highlighted row. Combobox and Context Menu carry the same pair, and the rule is the same in all three: the row's hover matches the panel it sits on.

Destructive has no frosted hover

Three states rather than four. A destructive row fills with base.destructive on hover and takes its label and icon to base.destructive-foreground, and a 70% version of that on a translucent panel would read as a weaker warning rather than a softer one. Twenty-two variants instead of twenty-four.

The panel

160 wide, two groups and a rule

The published menu is 160 by 233: two groups of four rows at 4px of padding with a separator between them. Colour swaps the surface and the ink together; Appearance drops the surface to 70%.

DropdownMenu / Menu · Components frameLive in the browser · drawn to match the file
Color
Appearance
My Account
Profile
Billing
Settings
Team
Invite users
New team
Log out
Color=Default · Appearance=Solid160 × 233 in the file
The other four

A button that owns the menu, and a row that opens another

2 variants · a 56 × 32 trigger plus the menu
My Account
Profile⇧⌘P
Billing⌘B
Settings⌘S
Team
Invite users
New team⌘T
Log out⇧⌘Q
Open

The only variant is whether the menu is showing. The trigger is a base.muted button that stays put in both, so the axis is genuinely about the panel and not about the button's pressed look. Its rows read Profile, Billing and Settings under a My Account heading and Invite users, New team and Log out under Team, with the shortcuts shadcn/ui gives them. They were Item one, two and three until now, so the main is usable as it comes.

4 variants · 290 × 28
SubTrigger Text
Active
Show Icon

Its corners were radius.sm where every Item beside it is radius.md, so two rows in the same menu rounded differently. Context Menu already had both at 8; this one now matches.

single · 302 × 24
Label Text

12 at weight 500 in base.muted-foreground. Shorter than a row at 24 rather than 28, so a heading takes less vertical room than the items under it.

single · 224 × 1

A bare 1px rule with no padding of its own, unlike Context Menu's, which wraps its line in an 8px board. Here the groups carry their own 4px, so the rule sits flush between them.

The usage frame

Four menus doing four jobs

1000 by 1040. The copy is the file's, and the submenu and the inverted player are live.

Menu
My account
Profile
Billing
Team
Sign out
In the file

Six components, thirty-two variants

Read straight out of the Penpot file. The axes below are the property names you will see in the variant dropdown.

DropdownMenu / ItemVariant × State × Show IconDefault · Shortcut · Destructive × Default · Hover · Hover (Translucent) · Disabled × No · Yes - Destructive has no frosted hover22
DropdownMenu / MenuColor × AppearanceDefault · Inverted × Solid · Translucent - 160 × 2334
DropdownMenu / SubTriggerActive × Show IconNo · Yes × Yes · No - 290 × 284
DropdownMenuOpenYes · No - a 56 × 32 trigger with the menu under it2
DropdownMenu / Label · Separatornonea 302 × 24 heading and a bare 1px rule2

Using the Dropdown Menu

Almost not at all, and that is the point: the rows are 312 wide here against 300 there, and this one adds a trigger button because a dropdown is opened by pressing something. Everything else, the states, the destructive treatment, the frosted panel, is the same vocabulary. Learn one and you have both.

It skips Hover (Translucent). A destructive row fills with base.destructive and takes its label and icon to base.destructive-foreground; a 70% version of that on a frosted panel reads as a weaker warning rather than a softer one. Twenty-two variants instead of twenty-four.

This one is a bare 1px rule with no padding of its own; Context Menu wraps its line in an 8px board. Here the two groups inside the menu carry their own 4px, so the rule sits flush between them and the spacing comes from the groups rather than from the rule.

Only whether the menu is showing. The trigger button is a base.muted pill that looks identical in both, so the variant is about the panel rather than about the button's pressed state. If you want a pressed trigger, that is Button's job.

They do now. All nine of them were base.muted-foreground, which is #737373 - fine on the white panel, about 3.4:1 on the #262626 inverted one, where a 12px label needs 4.5. They are bound to colors.muted-foreground-dark now, at #a1a1a1 and around 5.7:1. Worth checking on any component with an inverted surface: the foreground tokens flip when the background does, and muted text is where that gets forgotten.

Overlays · 32 variants