Components

Dropdown Menu

Glass menus that grow out of their trigger as a droplet and fold back into it through a teardrop neck, keeping the focus management of the shadcn dropdown menu.

Open the menu. The button swells into a droplet, then stretches into the panel.

Installation

pnpm dlx shadcn@latest add https://liquidcn.snmandela.com/r/liquid-dropdown-menu.json

The command copies these files into your project:

  • components/ui/liquid/dropdown-menu.tsx
  • components/ui/liquid/liquid.css
  • lib/liquid/motion.ts
  • lib/liquid/menu-morph.ts
  • lib/liquid/fusion.ts

It extends the shadcn dropdown-menu component, whichever primitive library yours is built on. If your project doesn't have it yet, the CLI adds it from shadcn's registry; if it does, yours stays as it is, and the CLI asks before replacing it.

Usage

import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/liquid/dropdown-menu"

<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <Button>Options</Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent>
    <DropdownMenuItem>Save to collection</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>

Examples

Checkable items

Radio groups, checkbox items, labels, and separators are the shadcn parts, restyled for glass.

Beside the trigger

Pass overlap={false} to open next to the button instead of over it. It still unfolds from the button.

API reference

DropdownMenuContent

Every prop of the shadcn DropdownMenuContent is forwarded. The other parts are re-exported unchanged, so imports stay the same.

PropTypeDefault
overlap

Open over the trigger and grow out of it, as iOS does.

booleantrue
side

Which way the panel extends from the trigger.

"top" | "right" | "bottom" | "left""bottom"
--liquid-morph-duration

Length of the unfold, set on any ancestor or the root.

CSS time520ms

Motion

ParameterValue
Unfold--liquid-morph-duration, through a droplet at 26% and an overshoot at 62%
ContentArrives magnified 1.3× and blurred 10 px, sharp by the end
Fold320 ms into an elongated droplet
Trigger bulge420 ms as the droplet lands
Still pressA press that moves less than 10 px never selects an item

Springs keep their velocity when interrupted, and every value here is removed under reduced motion. How the motion works

Accessibility

  • The base menu's semantics and focus management: opening from the keyboard focuses the first item, Escape returns focus to the trigger.
  • The press that opens the menu cannot select the item that appears under the finger. Press, drag, and release still selects, as on iOS.
  • Under reduced motion the panel appears and disappears without the droplet.