Overlay

DropdownMenu

Click-triggered dropdown menu with icons, keyboard shortcuts, checkbox/radio items, submenus, and custom rendering.

Basic Usage

<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>

Keyboard Shortcuts

<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

Grid: On · Rulers: Off

<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

<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>

Submenu

<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

<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

<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

SlotDescription
contentMain dropdown content
arrowArrow element
groupItem group container
separatorSeparator
labelGroup label
itemMenu item
itemLeadingIconIcon before label
itemLabelLabel text
itemTrailingKbdsKeyboard shortcuts area
itemIndicatorCheckbox/radio indicator
subTriggerSubmenu trigger
subContentSubmenu content

Snippets

SnippetDescription
childrenTrigger element (receives open)
headerCustom header (receives close)
footerCustom footer (receives close)
itemCustom item
contentReplace entire items rendering

Props

PropTypeDefault
itemsDropdownMenuItem[]-
radioGroupsRadioGroup[]-
size'xs'|'sm'|'md'|'lg'|'xl''md'
arrowboolean | ArrowPropsfalse
transitionbooleantrue
portalbooleantrue
openbooleanfalse
side'top'|'right'|'bottom'|'left''bottom'
align'start'|'center'|'end''start'
refHTMLElement | nullnull
classstring-
uiRecord<Slot, Class>-