Overlay

DropdownMenu

Display a floating menu of actions triggered by a button. Supports action items, checkbox items, radio groups, submenus, keyboard shortcuts, separators, and labels.

Playground

Experiment with different props in real-time.

Basic Usage

Pass an array of items with label and optional icon. The trigger is placed inside the children snippet.

<script lang="ts">
  import { DropdownMenu, Button } from 'sv5ui';

  const items = [
    { label: 'Edit', icon: 'lucide:pencil' },
    { label: 'Duplicate', icon: 'lucide:copy' },
    { label: 'Archive', icon: 'lucide:archive' },
    { label: 'Delete', icon: 'lucide:trash-2', color: 'error' }
  ];
</script>

<DropdownMenu {items}>
  <Button label="Actions" trailingIcon="lucide:chevron-down" />
</DropdownMenu>

With Keyboard Shortcuts

Use the kbds prop on items to display keyboard shortcut hints.

<script lang="ts">
  import { DropdownMenu, Button } from 'sv5ui';

  const items = [
    { label: 'Undo', icon: 'lucide:undo-2', kbds: ['meta', 'z'] },
    { label: 'Redo', icon: 'lucide:redo-2', kbds: ['meta', 'shift', 'z'] },
    { type: 'separator' },
    { label: 'Cut', icon: 'lucide:scissors', kbds: ['meta', 'x'] },
    { label: 'Copy', icon: 'lucide:copy', kbds: ['meta', 'c'] },
    { label: 'Paste', icon: 'lucide:clipboard', kbds: ['meta', 'v'] }
  ];
</script>

<DropdownMenu {items}>
  <Button label="Edit" trailingIcon="lucide:chevron-down" />
</DropdownMenu>

Checkbox Items

Set type: 'checkbox' on items to render toggleable checkboxes. Use onCheckedChange to update state.

<script lang="ts">
  import { DropdownMenu, Button } from 'sv5ui';

  let showStatusBar = $state(true);
  let showActivityBar = $state(false);
  let showPanel = $state(true);

  $effect(() => {
    items = [
      { type: 'label', label: 'Appearance' },
      { type: 'separator' },
      { type: 'checkbox', label: 'Status Bar', checked: showStatusBar, onCheckedChange: (v) => showStatusBar = v },
      { type: 'checkbox', label: 'Activity Bar', checked: showActivityBar, onCheckedChange: (v) => showActivityBar = v },
      { type: 'checkbox', label: 'Panel', checked: showPanel, onCheckedChange: (v) => showPanel = v }
    ];
  });

  let items = $state([
    { type: 'label', label: 'Appearance' },
    { type: 'separator' },
    { type: 'checkbox', label: 'Status Bar', checked: showStatusBar, onCheckedChange: (v) => showStatusBar = v },
    { type: 'checkbox', label: 'Activity Bar', checked: showActivityBar, onCheckedChange: (v) => showActivityBar = v },
    { type: 'checkbox', label: 'Panel', checked: showPanel, onCheckedChange: (v) => showPanel = v }
  ]);
</script>

<DropdownMenu {items}>
  <Button label="View" trailingIcon="lucide:chevron-down" />
</DropdownMenu>

Radio Items

Use type: 'radio' items with the radioGroups prop for single-select groups.

<script lang="ts">
  import { DropdownMenu, Button } from 'sv5ui';

  let theme = $state('system');

  const items = [
    { type: 'label', label: 'Theme' },
    { type: 'separator' },
    { type: 'radio', label: 'Light', value: 'light' },
    { type: 'radio', label: 'Dark', value: 'dark' },
    { type: 'radio', label: 'System', value: 'system' }
  ];

  const radioGroups = [
    {
      name: 'theme',
      value: theme,
      onValueChange: (v) => theme = v,
      items: items.filter((i) => i.type === 'radio')
    }
  ];
</script>

<DropdownMenu {items} {radioGroups}>
  <Button label="Theme" trailingIcon="lucide:chevron-down" />
</DropdownMenu>

With Separators & Labels

Use type: 'separator' and type: 'label' to organize items into logical groups.

<script lang="ts">
  import { DropdownMenu, Button } from 'sv5ui';

  const items = [
    { type: 'label', label: 'My Account' },
    { type: 'separator' },
    { label: 'Profile', icon: 'lucide:user' },
    { label: 'Settings', icon: 'lucide:settings' },
    { type: 'separator' },
    { label: 'Team', icon: 'lucide:users' },
    { label: 'Invite Users', icon: 'lucide:user-plus' },
    { type: 'separator' },
    { label: 'Logout', icon: 'lucide:log-out', color: 'error' }
  ];
</script>

<DropdownMenu {items}>
  <Button label="Account" trailingIcon="lucide:chevron-down" />
</DropdownMenu>

Submenu

Use type: 'sub' with a nested items array to create flyout submenus.

<script lang="ts">
  import { DropdownMenu, Button } from 'sv5ui';

  const items = [
    { label: 'New File', icon: 'lucide:file-plus' },
    { label: 'New Folder', icon: 'lucide:folder-plus' },
    { type: 'separator' },
    {
      type: 'sub',
      label: 'Share',
      icon: 'lucide:share-2',
      items: [
        { label: 'Email', icon: 'lucide:mail' },
        { label: 'Message', icon: 'lucide:message-square' },
        { type: 'separator' },
        { label: 'More...', icon: 'lucide:more-horizontal' }
      ]
    },
    { type: 'separator' },
    { label: 'Delete', icon: 'lucide:trash-2', color: 'error' }
  ];
</script>

<DropdownMenu {items}>
  <Button label="File" trailingIcon="lucide:chevron-down" />
</DropdownMenu>

Sizes

5 sizes from extra small to extra large.

<DropdownMenu {items} size="xs">...</DropdownMenu>
<DropdownMenu {items} size="sm">...</DropdownMenu>
<DropdownMenu {items} size="md">...</DropdownMenu>
<DropdownMenu {items} size="lg">...</DropdownMenu>
<DropdownMenu {items} size="xl">...</DropdownMenu>

Disabled Items

Set disabled: true on individual items to prevent interaction.

<script lang="ts">
  import { DropdownMenu, Button } from 'sv5ui';

  const items = [
    { label: 'Edit', icon: 'lucide:pencil' },
    { label: 'Duplicate', icon: 'lucide:copy', disabled: true },
    { label: 'Archive', icon: 'lucide:archive', disabled: true },
    { label: 'Delete', icon: 'lucide:trash-2', color: 'error' }
  ];
</script>

<DropdownMenu {items}>
  <Button label="Actions" trailingIcon="lucide:chevron-down" />
</DropdownMenu>

UI Slots

Use the ui prop to override classes on specific internal elements of the DropdownMenu.

SlotDescription
contentThe floating menu panel — controls background, border, shadow, and rounding
groupGroups related menu items together — controls spacing between groups
separatorVisual divider between groups — controls color and spacing
labelNon-interactive heading within a group — controls font size, weight, color
itemIndividual menu item row — controls padding, hover state, cursor
itemIconIcon element within a menu item — controls icon size and color
itemLabelText label within a menu item — controls font size and color
itemKbdKeyboard shortcut badge — controls font, background, rounding
itemIndicatorIndicator for checkbox/radio items — controls size and color
subTriggerSubmenu trigger item — controls hover state and arrow indicator
subTriggerIconArrow icon on the submenu trigger — controls icon size and color
subContentSubmenu floating panel — controls background, border, shadow
checkboxIndicatorCheckbox check mark indicator — controls icon and color
radioIndicatorRadio dot indicator — controls icon and color

Snippets

Use Svelte 5 snippets to customize specific parts of the DropdownMenu.

SnippetTypeDescription
childrenSnippetTrigger element — clicking opens the dropdown
contentSnippetCustom dropdown content — replaces default item rendering
headerSnippetCustom header above the menu items
footerSnippetCustom footer below the menu items
itemSnippetCustom renderer for individual menu items
itemLeadingSnippetCustom leading section of menu items
itemLabelSnippetCustom label section of menu items
itemTrailingSnippetCustom trailing section of menu items

Props

PropTypeDefault
openbooleanfalse
itemsDropdownMenuItem[][]
size'xs' | 'sm' | 'md' | 'lg' | 'xl''md'
arrowbooleanfalse
side'top' | 'right' | 'bottom' | 'left''bottom'
sideOffsetnumber4
align'start' | 'center' | 'end''start'
loopbooleantrue
radioGroupsRadioGroup[][]
transitionbooleantrue
portalbooleantrue
checkedIconstring'lucide:check'
submenuIconstring'lucide:chevron-right'
classstring-
uiRecord<Slot, Class>-