Presets

Blocks

Get PRO

Need premium blocks and templates? Upgrade to PRO and get access.

Upgrade
JoinLogin
Presets
Monochrome
Overview
  • Introduction
  • Components
  • Installation
Components
  • Accordion
  • Alert
  • Alert Dialog
  • Aspect Ratio
  • Avatar
  • Badge
  • Breadcrumb
  • Button
  • Button Group
  • CalendarNEW
  • Card
  • CarouselNEW
  • Checkbox
  • Collapsible
  • Dialog
  • Dropdown Menu
  • Empty
  • Field
  • Input
  • Input Group
  • Item
  • Kbd
  • Label
  • Native Select
  • Scroll Area
  • SelectNEW
  • Separator
  • SwitchNEW
  • Table
  • Tabs
  • Textarea
  • TooltipNEW

Dropdown Menu

PreviousNext

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-menu
npx sprawlify@latest add dropdown-menu
yarn sprawlify@latest add dropdown-menu
bunx --bun sprawlify@latest add dropdown-menu

Install the following dependencies:

pnpm add @sprawlify/primitives @sprawlify/solid
npm install @sprawlify/primitives @sprawlify/solid
yarn add @sprawlify/primitives @sprawlify/solid
bun add @sprawlify/primitives @sprawlify/solid

Add the following files to your project:

dropdown-menu.tsx
1import { DropdownMenu as DropdownMenuPrimitive } from "@sprawlify/solid/dropdown-menu";2import { cn } from "@/lib/utils";3import { CheckIcon, ChevronRightIcon } from "lucide-solid";4import type { ComponentProps } from "solid-js";5import { splitProps } from "solid-js";6import { Portal } from "solid-js/web";78function DropdownMenu(props: ComponentProps<typeof DropdownMenuPrimitive.Root>) {9  return (10    <DropdownMenuPrimitive.Root11      data-slot="dropdown-menu"12      positioning={{ offset: { mainAxis: 4 } }}13      {...props}14    />15  );16}1718function DropdownMenuPortal(props: ComponentProps<any>) {19  return <Portal data-slot="dropdown-menu-portal" {...props} />;20}2122function DropdownMenuTrigger(props: ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {23  return <DropdownMenuPrimitive.Trigger data-slot="dropdown-menu-trigger" {...props} />;24}2526function DropdownMenuContent(props: ComponentProps<typeof DropdownMenuPrimitive.Content>) {27  const [local, others] = splitProps(props, ["class"]);28  return (29    <Portal>30      <DropdownMenuPrimitive.Positioner>31        <DropdownMenuPrimitive.Content32          data-slot="dropdown-menu-content"33          class={cn(34            "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",35            local.class,36          )}37          {...others}38        />39      </DropdownMenuPrimitive.Positioner>40    </Portal>41  );42}4344function DropdownMenuGroup(props: ComponentProps<typeof DropdownMenuPrimitive.ItemGroup>) {45  return <DropdownMenuPrimitive.ItemGroup data-slot="dropdown-menu-group" {...props} />;46}4748function DropdownMenuItem(49  props: ComponentProps<typeof DropdownMenuPrimitive.Item> & {50    inset?: boolean;51    variant?: "default" | "destructive";52  },53) {54  const [local, others] = splitProps(props, ["class", "inset", "variant"]);55  const variant = () => local.variant ?? "default";5657  return (58    <DropdownMenuPrimitive.Item59      data-slot="dropdown-menu-item"60      data-inset={local.inset}61      data-variant={variant()}62      class={cn(63        "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",64        "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",65        local.class,66      )}67      {...others}68    />69  );70}7172function DropdownMenuCheckboxItem(73  props: ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem> & {74    inset?: boolean;75  },76) {77  const [local, others] = splitProps(props, ["class", "children", "checked", "inset"]);7879  return (80    <DropdownMenuPrimitive.CheckboxItem81      data-slot="dropdown-menu-checkbox-item"82      data-inset={local.inset}83      class={cn(84        "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",85        local.class,86      )}87      checked={local.checked}88      {...others}89    >90      <span91        class="absolute right-2 flex items-center justify-center pointer-events-none"92        data-slot="dropdown-menu-checkbox-item-indicator"93      >94        <DropdownMenuPrimitive.ItemIndicator>95          <CheckIcon />96        </DropdownMenuPrimitive.ItemIndicator>97      </span>98      {local.children}99    </DropdownMenuPrimitive.CheckboxItem>100  );101}102103function DropdownMenuRadioGroup(104  props: ComponentProps<typeof DropdownMenuPrimitive.RadioItemGroup>,105) {106  return <DropdownMenuPrimitive.RadioItemGroup data-slot="dropdown-menu-radio-group" {...props} />;107}108109function DropdownMenuRadioItem(110  props: ComponentProps<typeof DropdownMenuPrimitive.RadioItem> & {111    inset?: boolean;112  },113) {114  const [local, others] = splitProps(props, ["class", "children", "inset"]);115116  return (117    <DropdownMenuPrimitive.RadioItem118      data-slot="dropdown-menu-radio-item"119      data-inset={local.inset}120      class={cn(121        "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",122        local.class,123      )}124      {...others}125    >126      <span127        class="absolute right-2 flex items-center justify-center pointer-events-none"128        data-slot="dropdown-menu-radio-item-indicator"129      >130        <DropdownMenuPrimitive.ItemIndicator>131          <CheckIcon />132        </DropdownMenuPrimitive.ItemIndicator>133      </span>134      {local.children}135    </DropdownMenuPrimitive.RadioItem>136  );137}138139function DropdownMenuLabel(140  props: ComponentProps<typeof DropdownMenuPrimitive.ItemGroupLabel> & {141    inset?: boolean;142  },143) {144  const [local, others] = splitProps(props, ["class", "inset"]);145146  return (147    <DropdownMenuPrimitive.ItemGroupLabel148      data-slot="dropdown-menu-label"149      data-inset={local.inset}150      class={cn(151        "text-muted-foreground px-1.5 py-1 text-xs font-medium data-inset:pl-7",152        local.class,153      )}154      {...others}155    />156  );157}158159function DropdownMenuSeparator(props: ComponentProps<typeof DropdownMenuPrimitive.Separator>) {160  const [local, others] = splitProps(props, ["class"]);161162  return (163    <DropdownMenuPrimitive.Separator164      data-slot="dropdown-menu-separator"165      class={cn("bg-border -mx-1 my-1 h-px", local.class)}166      {...others}167    />168  );169}170171function DropdownMenuShortcut(props: ComponentProps<"span">) {172  const [local, others] = splitProps(props, ["class"]);173174  return (175    <span176      data-slot="dropdown-menu-shortcut"177      class={cn(178        "text-muted-foreground group-focus/dropdown-menu-item:text-accent-foreground ml-auto text-xs tracking-widest",179        local.class,180      )}181      {...others}182    />183  );184}185186function DropdownMenuSub(props: ComponentProps<typeof DropdownMenuPrimitive.Root>) {187  return <DropdownMenuPrimitive.Root data-slot="dropdown-menu-sub" {...props} />;188}189190function DropdownMenuSubTrigger(191  props: ComponentProps<typeof DropdownMenuPrimitive.TriggerItem> & {192    inset?: boolean;193  },194) {195  const [local, others] = splitProps(props, ["class", "inset", "children"]);196197  return (198    <DropdownMenuPrimitive.TriggerItem199      data-slot="dropdown-menu-sub-trigger"200      data-inset={local.inset}201      class={cn(202        "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",203        local.class,204      )}205      {...others}206    >207      {local.children}208      <ChevronRightIcon class="ml-auto" />209    </DropdownMenuPrimitive.TriggerItem>210  );211}212213function DropdownMenuSubContent(props: ComponentProps<typeof DropdownMenuPrimitive.Content>) {214  const [local, others] = splitProps(props, ["class"]);215216  return (217    <DropdownMenuPrimitive.Positioner>218      <DropdownMenuPrimitive.Content219        data-slot="dropdown-menu-sub-content"220        class={cn(221          "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",222          local.class,223        )}224        {...others}225      />226    </DropdownMenuPrimitive.Positioner>227  );228}229230export {231  DropdownMenu,232  DropdownMenuPortal,233  DropdownMenuTrigger,234  DropdownMenuContent,235  DropdownMenuGroup,236  DropdownMenuLabel,237  DropdownMenuItem,238  DropdownMenuCheckboxItem,239  DropdownMenuRadioGroup,240  DropdownMenuRadioItem,241  DropdownMenuSeparator,242  DropdownMenuShortcut,243  DropdownMenuSub,244  DropdownMenuSubTrigger,245  DropdownMenuSubContent,246};247

Update 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
3    asChild={(props) => (
4      <Button variant="outline" {...props()}>
5        Open
6      </Button>
7    )}
8  />
9  <DropdownMenuContent>
10    <DropdownMenuGroup>
11      <DropdownMenuLabel>My Account</DropdownMenuLabel>
12      <DropdownMenuItem>Profile</DropdownMenuItem>
13      <DropdownMenuItem>Billing</DropdownMenuItem>
14    </DropdownMenuGroup>
15    <DropdownMenuSeparator />
16    <DropdownMenuGroup>
17      <DropdownMenuItem>Team</DropdownMenuItem>
18      <DropdownMenuItem>Subscription</DropdownMenuItem>
19    </DropdownMenuGroup>
20  </DropdownMenuContent>
21</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 { createSignal } from "solid-js";2import { Button } from "@/components/ui/button";3import {4  DropdownMenu,

Checkboxes Icons

Add icons to checkbox items.

1import { createSignal } from "solid-js";2import { Button } from "@/components/ui/button";3import {4  DropdownMenu,

Complex

A richer example combining groups, icons, and submenus.

1import { createSignal } from "solid-js";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 { createSignal } from "solid-js";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 IconsShortcutsSubmenu

Get PRO

Need premium blocks and templates? Upgrade to PRO and get access.