Displays a menu to the user — such as a set of actions or functions — triggered by a button.
1import { Button } from "@/components/ui/button";2import {3 DropdownMenu,4 DropdownMenuContent,Installation
pnpm dlx sprawlify@latest add dropdown-menunpx sprawlify@latest add dropdown-menuyarn sprawlify@latest add dropdown-menubunx --bun sprawlify@latest add dropdown-menu
Install the following dependencies:
pnpm add @sprawlify/primitives @sprawlify/reactnpm install @sprawlify/primitives @sprawlify/reactyarn add @sprawlify/primitives @sprawlify/reactbun add @sprawlify/primitives @sprawlify/react
Add the following files to your project:
1"use client";23import * as React from "react";4import { DropdownMenu as DropdownMenuPrimitive } from "@sprawlify/react/dropdown-menu";5import { cn } from "@/lib/utils";6import { CheckIcon, ChevronRightIcon } from "lucide-react";7import { Portal } from "@sprawlify/react/portal";8import { sprawlify } from "@sprawlify/react";910function DropdownMenu({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {11 return (12 <DropdownMenuPrimitive.Root13 data-slot="dropdown-menu"14 positioning={{ offset: { mainAxis: 4 } }}15 {...props}16 />17 );18}1920function DropdownMenuPortal({ ...props }: React.ComponentProps<typeof Portal>) {21 return <Portal data-slot="dropdown-menu-portal" {...props} />;22}2324function DropdownMenuTrigger({25 ...props26}: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {27 return <DropdownMenuPrimitive.Trigger data-slot="dropdown-menu-trigger" {...props} />;28}2930function DropdownMenuContent({31 className,32 ...props33}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {34 return (35 <Portal>36 <DropdownMenuPrimitive.Positioner>37 <DropdownMenuPrimitive.Content38 data-slot="dropdown-menu-content"39 className={cn(40 "focus-visible:outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 bg-popover text-popover-foreground min-w-32 rounded-lg p-1 shadow-md ring-1 duration-100 z-(--z-index) max-h-(--available-height) w-(--reference-width) origin-(--transform-origin) overflow-x-hidden overflow-y-auto data-[state=closed]:overflow-hidden",41 className,42 )}43 {...props}44 />45 </DropdownMenuPrimitive.Positioner>46 </Portal>47 );48}4950function DropdownMenuGroup({51 ...props52}: React.ComponentProps<typeof DropdownMenuPrimitive.ItemGroup>) {53 return <DropdownMenuPrimitive.ItemGroup data-slot="dropdown-menu-group" {...props} />;54}5556function DropdownMenuItem({57 className,58 inset,59 variant = "default",60 ...props61}: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {62 inset?: boolean;63 variant?: "default" | "destructive";64}) {65 return (66 <DropdownMenuPrimitive.Item67 data-slot="dropdown-menu-item"68 data-inset={inset}69 data-variant={variant}70 className={cn(71 "gap-1.5 rounded-md px-1.5 py-1 text-sm data-inset:pl-7 [&_svg:not([class*='size-'])]:size-4 group/dropdown-menu-item relative flex cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",72 "data-[variant=destructive]:text-destructive data-highlighted:bg-accent data-highlighted:text-accent-foreground data-[variant=destructive]:data-highlighted:bg-destructive/10 dark:data-[variant=destructive]:data-highlighted:bg-destructive/20 data-[variant=destructive]:data-highlighted:text-destructive data-[variant=destructive]:data-highlighted:*:[svg]:text-destructive not-data-[variant=destructive]:data-highlighted:**:text-accent-foreground",73 className,74 )}75 {...props}76 />77 );78}7980function DropdownMenuCheckboxItem({81 className,82 children,83 checked,84 inset,85 ...props86}: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem> & {87 inset?: boolean;88}) {89 return (90 <DropdownMenuPrimitive.CheckboxItem91 data-slot="dropdown-menu-checkbox-item"92 data-inset={inset}93 className={cn(94 "focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm data-inset:pl-7 [&_svg:not([class*='size-'])]:size-4 relative flex cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",95 className,96 )}97 checked={checked}98 {...props}99 >100 <span101 className="absolute right-2 flex items-center justify-center pointer-events-none"102 data-slot="dropdown-menu-checkbox-item-indicator"103 >104 <DropdownMenuPrimitive.ItemIndicator>105 <CheckIcon />106 </DropdownMenuPrimitive.ItemIndicator>107 </span>108 {children}109 </DropdownMenuPrimitive.CheckboxItem>110 );111}112113function DropdownMenuRadioGroup({114 ...props115}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItemGroup>) {116 return <DropdownMenuPrimitive.RadioItemGroup data-slot="dropdown-menu-radio-group" {...props} />;117}118119function DropdownMenuRadioItem({120 className,121 children,122 inset,123 ...props124}: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem> & {125 inset?: boolean;126}) {127 return (128 <DropdownMenuPrimitive.RadioItem129 data-slot="dropdown-menu-radio-item"130 data-inset={inset}131 className={cn(132 "focus:bg-accent focus:text-accent-foreground focus:**:text-accent-foreground gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm data-inset:pl-7 [&_svg:not([class*='size-'])]:size-4 relative flex cursor-default items-center outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0",133 className,134 )}135 {...props}136 >137 <span138 className="absolute right-2 flex items-center justify-center pointer-events-none"139 data-slot="dropdown-menu-radio-item-indicator"140 >141 <DropdownMenuPrimitive.ItemIndicator>142 <CheckIcon />143 </DropdownMenuPrimitive.ItemIndicator>144 </span>145 {children}146 </DropdownMenuPrimitive.RadioItem>147 );148}149150function DropdownMenuLabel({151 className,152 inset,153 ...props154}: React.ComponentProps<typeof DropdownMenuPrimitive.ItemGroupLabel> & {155 inset?: boolean;156}) {157 return (158 <DropdownMenuPrimitive.ItemGroupLabel159 data-slot="dropdown-menu-label"160 data-inset={inset}161 className={cn(162 "text-muted-foreground px-1.5 py-1 text-xs font-medium data-inset:pl-7",163 className,164 )}165 {...props}166 />167 );168}169170function DropdownMenuSeparator({171 className,172 ...props173}: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>) {174 return (175 <DropdownMenuPrimitive.Separator176 data-slot="dropdown-menu-separator"177 className={cn("bg-border -mx-1 my-1 h-px", className)}178 {...props}179 />180 );181}182183function DropdownMenuShortcut({184 className,185 ...props186}: React.ComponentProps<typeof sprawlify.span>) {187 return (188 <sprawlify.span189 data-slot="dropdown-menu-shortcut"190 className={cn(191 "text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground ml-auto text-xs tracking-widest",192 className,193 )}194 {...props}195 />196 );197}198199function DropdownMenuSub({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {200 return <DropdownMenuPrimitive.Root data-slot="dropdown-menu-sub" {...props} />;201}202203function DropdownMenuSubTrigger({204 className,205 inset,206 children,207 ...props208}: React.ComponentProps<typeof DropdownMenuPrimitive.TriggerItem> & {209 inset?: boolean;210}) {211 return (212 <DropdownMenuPrimitive.TriggerItem213 data-slot="dropdown-menu-sub-trigger"214 data-inset={inset}215 className={cn(216 "w-full data-[state=open]:bg-accent data-[state=open]:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground gap-1.5 rounded-md px-1.5 py-1 text-sm data-inset:pl-7 [&_svg:not([class*='size-'])]:size-4 flex cursor-default items-center outline-hidden select-none [&_svg]:pointer-events-none [&_svg]:shrink-0",217 className,218 )}219 {...props}220 >221 {children}222 <ChevronRightIcon className="ml-auto" />223 </DropdownMenuPrimitive.TriggerItem>224 );225}226227function DropdownMenuSubContent({228 className,229 ...props230}: React.ComponentProps<typeof DropdownMenuPrimitive.Content>) {231 return (232 <Portal>233 <DropdownMenuPrimitive.Positioner>234 <DropdownMenuPrimitive.Content235 data-slot="dropdown-menu-sub-content"236 className={cn(237 "focus-visible:outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 ring-foreground/10 bg-popover text-popover-foreground min-w-[96px] rounded-lg p-1 shadow-lg ring-1 duration-100 origin-(--transform-origin) overflow-hidden",238 className,239 )}240 {...props}241 />242 </DropdownMenuPrimitive.Positioner>243 </Portal>244 );245}246247export {248 DropdownMenu,249 DropdownMenuPortal,250 DropdownMenuTrigger,251 DropdownMenuContent,252 DropdownMenuGroup,253 DropdownMenuLabel,254 DropdownMenuItem,255 DropdownMenuCheckboxItem,256 DropdownMenuRadioGroup,257 DropdownMenuRadioItem,258 DropdownMenuSeparator,259 DropdownMenuShortcut,260 DropdownMenuSub,261 DropdownMenuSubTrigger,262 DropdownMenuSubContent,263};264Update the import paths to match your project setup.
Usage
1import {
2 DropdownMenu,
3 DropdownMenuPortal,
4 DropdownMenuTrigger,
5 DropdownMenuContent,
6 DropdownMenuGroup,
7 DropdownMenuLabel,
8 DropdownMenuItem,
9 DropdownMenuCheckboxItem,
10 DropdownMenuRadioGroup,
11 DropdownMenuRadioItem,
12 DropdownMenuSeparator,
13 DropdownMenuShortcut,
14 DropdownMenuSub,
15 DropdownMenuSubTrigger,
16 DropdownMenuSubContent
17} from "@/components/ui/dropdown-menu"1<DropdownMenu>
2 <DropdownMenuTrigger asChild>
3 <Button variant="outline">Open</Button>
4 </DropdownMenuTrigger>
5 <DropdownMenuContent>
6 <DropdownMenuGroup>
7 <DropdownMenuLabel>My Account</DropdownMenuLabel>
8 <DropdownMenuItem>Profile</DropdownMenuItem>
9 <DropdownMenuItem>Billing</DropdownMenuItem>
10 </DropdownMenuGroup>
11 <DropdownMenuSeparator />
12 <DropdownMenuGroup>
13 <DropdownMenuItem>Team</DropdownMenuItem>
14 <DropdownMenuItem>Subscription</DropdownMenuItem>
15 </DropdownMenuGroup>
16 </DropdownMenuContent>
17</DropdownMenu>Examples
Avatar
An account switcher dropdown triggered by an avatar.
1import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";2import { Button } from "@/components/ui/button";3import {4 DropdownMenu,Basic
A basic dropdown menu with labels and separators.
1import { Button } from "@/components/ui/button";2import {3 DropdownMenu,4 DropdownMenuContent,Checkboxes
Use DropdownMenuCheckboxItem for toggles.
1import * as React from "react";2import { Button } from "@/components/ui/button";3import {4 DropdownMenu,Checkboxes Icons
Add icons to checkbox items.
1import * as React from "react";2import { Button } from "@/components/ui/button";3import {4 DropdownMenu,Complex
A richer example combining groups, icons, and submenus.
1import * as React from "react";2import { Button } from "@/components/ui/button";3import {4 DropdownMenu,Destructive
Use variant="destructive" for irreversible actions.
1import { Button } from "@/components/ui/button";2import {3 DropdownMenu,4 DropdownMenuContent,Icons
Combine icons with labels for quick scanning.
1import { Button } from "@/components/ui/button";2import {3 DropdownMenu,4 DropdownMenuContent,Radio Icons
Show radio options with icons.
1import * as React from "react";2import { Button } from "@/components/ui/button";3import {4 DropdownMenu,Shortcuts
Add DropdownMenuShortcut to show keyboard hints.
1import { Button } from "@/components/ui/button";2import {3 DropdownMenu,4 DropdownMenuContent,Submenu
Use DropdownMenuSub to nest secondary actions.
1import { Button } from "@/components/ui/button";2import {3 DropdownMenu,4 DropdownMenuContent,On This Page
InstallationUsageExamplesAvatarBasicCheckboxesCheckboxes IconsComplexDestructiveIconsRadio IconsShortcutsSubmenuGet PRO
Need premium blocks and templates? Upgrade to PRO and get access.