DropdownMenu
A list of actions behind one trigger, with typeahead and arrow keys.
Last action: Nothing yet
Source
<script lang="ts">
import 'portal-bits/styles.css';
import 'portal-bits/tokens.css';
import type { Snippet } from 'svelte';
let { children }: { children: Snippet } = $props();
</script>
{@render children()}
<script lang="ts">
import DropdownMenuExample from './DropdownMenuExample.svelte';
</script>
<DropdownMenuExample align={"end"} shortcuts={true} />
<script lang="ts">
import { DropdownMenu } from 'portal-bits';
import { Copy, Ellipsis, Pencil, Share2, Trash2 } from '@lucide/svelte';
let {
align = 'end',
shortcuts = true,
}: { align?: 'start' | 'center' | 'end'; shortcuts?: boolean } = $props();
let last = $state('Nothing yet');
</script>
<div class="stack">
<DropdownMenu
label="Draft actions"
{align}
items={[
{
label: 'Rename',
icon: Pencil,
shortcut: shortcuts ? 'R' : undefined,
onSelect: () => (last = 'Rename'),
},
{
label: 'Duplicate',
icon: Copy,
shortcut: shortcuts ? 'D' : undefined,
onSelect: () => (last = 'Duplicate'),
},
{ label: 'Share', icon: Share2, onSelect: () => (last = 'Share') },
{ type: 'separator' },
{ label: 'Delete', icon: Trash2, tone: 'danger', onSelect: () => (last = 'Delete') },
]}
>
{#snippet trigger()}<Ellipsis size={17} />{/snippet}
</DropdownMenu>
<p aria-live="polite">Last action: {last}</p>
</div>
<style>
.stack {
display: grid;
justify-items: center;
gap: 12px;
}
p {
margin: 0;
}
</style>
API reference
These tables list the props and snippets that DropdownMenu declares. Attributes passed through to an element or primitive are listed under Forwarded attributes, not here.
Props
| Name | Type | Default | Required | Binding | Description |
|---|---|---|---|---|---|
label | string | None | Yes | One-way | Names the trigger with `aria-label`. |
items | MenuEntry[] | None | Yes | One-way | Items as `{ label, onSelect?, icon?, shortcut?, tone?, disabled? }`, or `{ type: 'separator' }`. |
open | boolean | false | No | Bindable | Whether the menu is open. |
align | 'start' | 'center' | 'end' | end | No | One-way | Alignment against the trigger. |
side | 'top' | 'right' | 'bottom' | 'left' | bottom | No | One-way | Preferred side of the trigger. |
theme | 'light' | 'dark' | light | No | One-way | Theme scope for the portaled content. Portaled content does not inherit the page scope. |
triggerClass | string | Secondary 40px icon button | No | One-way | Replaces the trigger classes. |
Snippets
| Name | Type | Default | Required | Binding | Description |
|---|---|---|---|---|---|
trigger | Snippet | None | Yes | One-way | The trigger content, usually an icon. |
Forwarded attributes
None. DropdownMenu forwards no attributes.
The primitive underneath is a Bits UI peer dependency. Its own options are documented in the Bits UI Dropdown Menu documentation. Only the props listed on this page are part of the DropdownMenu contract. No data attributes are documented as stable.
Limits
- Items are actions. Checkbox items, radio items, and submenus are not supported.
- `shortcut` is a visible hint only. The menu does not bind the key.
- The item rows and danger tone are an adaptation of the popover surface.