Kumo Svelte
  • Home
  • Installation
  • Colors
  • Accessibility
  • Changelog
  • Autocomplete
  • Badge
  • Banner
  • Breadcrumbs
  • Button
  • Checkbox
  • Clipboard Text
  • Cloudflare Logo
  • CodeHighlighted
  • Collapsible
  • Combobox
  • Command Palette
  • Date Picker
  • Dialog
  • Dropdown
  • Empty
  • Flow
  • Grid
  • Input
  • InputArea
  • InputGroup
  • Label
  • Layer Card
  • Link
  • Loader
  • MenuBar
  • Meter
  • Pagination
  • Popover
  • Radio
  • Select
  • Sensitive Input
  • Sidebar
  • Skeleton Line
  • Switch
  • Table
  • Table of Contents
  • Tabs
  • Text
  • Toast
  • Toolbar
  • Tooltip
  • Charts
  • Colors
  • Timeseries
  • Maps
  • Sankey
  • Custom Chart
  • Page Header
  • Resource List
  • Delete Resource
Dropdown Menu
kumo-svelte

Dropdown Menu

Displays a menu to the user—such as a set of actions or functions—triggered by a button.

<script lang="ts">
  import { Button } from "kumo-svelte/components/button";
  import * as DropdownMenu from "kumo-svelte/components/dropdown";
  import PlusIcon from "phosphor-svelte/lib/PlusIcon";
</script>

<DropdownMenu.Root>
  <DropdownMenu.Trigger>
    {#snippet child({ props })}
      <Button {...props} icon={PlusIcon}>Add</Button>
    {/snippet}
  </DropdownMenu.Trigger>
  <DropdownMenu.Content>
    <DropdownMenu.Item>Worker</DropdownMenu.Item>
    <DropdownMenu.Item>Pages</DropdownMenu.Item>
    <DropdownMenu.Item>KV Namespace</DropdownMenu.Item>
  </DropdownMenu.Content>
</DropdownMenu.Root>

Import

import * as DropdownMenu from "kumo-svelte/components/dropdown";

Usage

<script lang="ts">
  import { Button } from "kumo-svelte/components/button";
  import * as DropdownMenu from "kumo-svelte/components/dropdown";
</script>

<DropdownMenu.Root>
  <DropdownMenu.Trigger>
    {#snippet child({ props })}
      <Button {...props}>Menu</Button>
    {/snippet}
  </DropdownMenu.Trigger>
  <DropdownMenu.Content>
    <DropdownMenu.Item onclick={() => console.log("edit")}>Edit</DropdownMenu.Item>
    <DropdownMenu.Item onclick={() => console.log("duplicate")}>Duplicate</DropdownMenu.Item>
    <DropdownMenu.Separator />
    <DropdownMenu.Item variant="danger" onclick={() => console.log("delete")}>Delete</DropdownMenu.Item>
  </DropdownMenu.Content>
</DropdownMenu.Root>

Examples

Basic Dropdown

<script lang="ts">
  import { Button } from "kumo-svelte/components/button";
  import * as DropdownMenu from "kumo-svelte/components/dropdown";
  import PlusIcon from "phosphor-svelte/lib/PlusIcon";
</script>

<DropdownMenu.Root>
  <DropdownMenu.Trigger>
    {#snippet child({ props })}
      <Button {...props} icon={PlusIcon}>Add</Button>
    {/snippet}
  </DropdownMenu.Trigger>
  <DropdownMenu.Content>
    <DropdownMenu.Item>Worker</DropdownMenu.Item>
    <DropdownMenu.Item>Pages</DropdownMenu.Item>
    <DropdownMenu.Item>KV Namespace</DropdownMenu.Item>
  </DropdownMenu.Content>
</DropdownMenu.Root>

Inset Items

Use inset on items without an icon to align their text with items that have one.

<script lang="ts">
  import { Button } from "kumo-svelte/components/button";
  import * as DropdownMenu from "kumo-svelte/components/dropdown";
  import CopyIcon from "phosphor-svelte/lib/CopyIcon";
  import PencilSimpleIcon from "phosphor-svelte/lib/PencilSimpleIcon";
  import TrashIcon from "phosphor-svelte/lib/TrashIcon";
</script>

{#snippet pencilIcon()}
  <PencilSimpleIcon size={16} />
{/snippet}

{#snippet copyIcon()}
  <CopyIcon size={16} />
{/snippet}

{#snippet trashIcon()}
  <TrashIcon size={16} />
{/snippet}

<DropdownMenu.Root>
  <DropdownMenu.Trigger>
    {#snippet child({ props })}
      <Button {...props}>Edit</Button>
    {/snippet}
  </DropdownMenu.Trigger>
  <DropdownMenu.Content>
    <DropdownMenu.Item icon={pencilIcon}>Rename</DropdownMenu.Item>
    <DropdownMenu.Item icon={copyIcon}>Duplicate</DropdownMenu.Item>
    <DropdownMenu.Separator />
    <DropdownMenu.Item inset>Move to folder</DropdownMenu.Item>
    <DropdownMenu.Item inset>Add to favorites</DropdownMenu.Item>
    <DropdownMenu.Separator />
    <DropdownMenu.Item icon={trashIcon} variant="danger">Delete</DropdownMenu.Item>
  </DropdownMenu.Content>
</DropdownMenu.Root>

Handling Item Clicks

Use onclick on DropdownMenu.Item to handle actions. Each item receives a standard Svelte DOM event handler.

<script lang="ts">
  import { Button } from "kumo-svelte/components/button";
  import * as DropdownMenu from "kumo-svelte/components/dropdown";
  import CopyIcon from "phosphor-svelte/lib/CopyIcon";
  import PencilSimpleIcon from "phosphor-svelte/lib/PencilSimpleIcon";
  import TrashIcon from "phosphor-svelte/lib/TrashIcon";

  let lastAction = $state<string | null>(null);
</script>

{#snippet copyIcon()}
  <CopyIcon size={16} />
{/snippet}

{#snippet pencilIcon()}
  <PencilSimpleIcon size={16} />
{/snippet}

{#snippet trashIcon()}
  <TrashIcon size={16} />
{/snippet}

<div class="flex flex-col items-start gap-2">
  <DropdownMenu.Root>
    <DropdownMenu.Trigger>
      {#snippet child({ props })}
        <Button {...props}>Actions</Button>
      {/snippet}
    </DropdownMenu.Trigger>
    <DropdownMenu.Content>
      <DropdownMenu.Item icon={copyIcon} onclick={() => (lastAction = "Duplicated")}>Duplicate</DropdownMenu.Item>
      <DropdownMenu.Item icon={pencilIcon} onclick={() => (lastAction = "Renamed")}>Rename</DropdownMenu.Item>
      <DropdownMenu.Separator />
      <DropdownMenu.Item icon={trashIcon} variant="danger" onclick={() => (lastAction = "Deleted")}>Delete</DropdownMenu.Item>
    </DropdownMenu.Content>
  </DropdownMenu.Root>
  {#if lastAction}
    <p class="text-sm text-kumo-subtle">Last action: <span class="text-kumo-default">{lastAction}</span></p>
  {/if}
</div>

Checkbox Items

Use DropdownMenu.CheckboxItem for toggleable options that can be independently checked or unchecked.

<script lang="ts">
  import { Button } from "kumo-svelte/components/button";
  import * as DropdownMenu from "kumo-svelte/components/dropdown";
  let showSidebar = $state(true);
  let showLineNumbers = $state(false);
  let wordWrap = $state(true);
</script>

<DropdownMenu.Root>
  <DropdownMenu.Trigger>
    {#snippet child({ props })}
      <Button {...props}>View Options</Button>
    {/snippet}
  </DropdownMenu.Trigger>
  <DropdownMenu.Content>
    <DropdownMenu.Group>
      <DropdownMenu.Label>Display</DropdownMenu.Label>
      <DropdownMenu.CheckboxItem bind:checked={showSidebar}>Show sidebar</DropdownMenu.CheckboxItem>
      <DropdownMenu.CheckboxItem bind:checked={showLineNumbers}>Show line numbers</DropdownMenu.CheckboxItem>
      <DropdownMenu.CheckboxItem bind:checked={wordWrap}>Word wrap</DropdownMenu.CheckboxItem>
    </DropdownMenu.Group>
  </DropdownMenu.Content>
</DropdownMenu.Root>

Nested Menu with Radio Selection

Use DropdownMenu.Sub, DropdownMenu.SubTrigger, and DropdownMenu.SubContent to create nested submenus. For single-selection lists like language or timezone, use DropdownMenu.RadioGroup and DropdownMenu.RadioItem.

<script lang="ts">
  import { Button } from "kumo-svelte/components/button";
  import * as DropdownMenu from "kumo-svelte/components/dropdown";
  import CreditCardIcon from "phosphor-svelte/lib/CreditCardIcon";
  import MoonIcon from "phosphor-svelte/lib/MoonIcon";
  import SignOutIcon from "phosphor-svelte/lib/SignOutIcon";
  import UserIcon from "phosphor-svelte/lib/UserIcon";

  const languages = [
    { code: "de", label: "Deutsch" },
    { code: "en", label: "English" },
    { code: "es", label: "Español" },
    { code: "fr", label: "Français" },
    { code: "it", label: "Italiano" },
    { code: "pt", label: "Português" },
    { code: "ko", label: "한국어" },
    { code: "ja", label: "日本語" },
    { code: "zh-CN", label: "简体中文" },
    { code: "zh-TW", label: "繁體中文" },
  ];
  const timezones = [
    { value: "America/Los_Angeles", label: "Pacific Time (PT)" },
    { value: "America/Denver", label: "Mountain Time (MT)" },
    { value: "America/Chicago", label: "Central Time (CT)" },
    { value: "America/New_York", label: "Eastern Time (ET)" },
    { value: "Europe/London", label: "Greenwich Mean Time (GMT)" },
    { value: "Europe/Paris", label: "Central European Time (CET)" },
    { value: "Asia/Tokyo", label: "Japan Standard Time (JST)" },
  ];
  let language = $state("en");
  let timezone = $state("America/Los_Angeles");
</script>

{#snippet userIcon()}
  <UserIcon size={16} />
{/snippet}

{#snippet cardIcon()}
  <CreditCardIcon size={16} />
{/snippet}

{#snippet moonIcon()}
  <MoonIcon size={16} />
{/snippet}

{#snippet signOutIcon()}
  <SignOutIcon size={16} />
{/snippet}

<DropdownMenu.Root>
  <DropdownMenu.Trigger>
    {#snippet child({ props })}
      <Button {...props} icon={UserIcon}>Account</Button>
    {/snippet}
  </DropdownMenu.Trigger>
  <DropdownMenu.Content>
    <DropdownMenu.Item icon={userIcon}>Profile</DropdownMenu.Item>
    <DropdownMenu.Item icon={cardIcon}>Billing</DropdownMenu.Item>
    <DropdownMenu.Item icon={moonIcon}>Dark mode</DropdownMenu.Item>
    <DropdownMenu.Sub>
      <DropdownMenu.SubTrigger>Language</DropdownMenu.SubTrigger>
      <DropdownMenu.SubContent>
        <DropdownMenu.Group>
          <DropdownMenu.RadioGroup bind:value={language}>
            {#each languages as item}
              <DropdownMenu.RadioItem value={item.code}>{item.label}</DropdownMenu.RadioItem>
            {/each}
          </DropdownMenu.RadioGroup>
        </DropdownMenu.Group>
      </DropdownMenu.SubContent>
    </DropdownMenu.Sub>
    <DropdownMenu.Sub>
      <DropdownMenu.SubTrigger>Set Timezone</DropdownMenu.SubTrigger>
      <DropdownMenu.SubContent>
        <DropdownMenu.Group>
          <DropdownMenu.RadioGroup bind:value={timezone}>
            {#each timezones as item}
              <DropdownMenu.RadioItem value={item.value}>{item.label}</DropdownMenu.RadioItem>
            {/each}
          </DropdownMenu.RadioGroup>
        </DropdownMenu.Group>
      </DropdownMenu.SubContent>
    </DropdownMenu.Sub>
    <DropdownMenu.Separator />
    <DropdownMenu.Item icon={signOutIcon} variant="danger">Log out</DropdownMenu.Item>
  </DropdownMenu.Content>
</DropdownMenu.Root>

Custom Trigger with Avatar

Use the trigger child snippet to customize the trigger element while preserving accessible trigger props.

<script lang="ts">
  import * as DropdownMenu from "kumo-svelte/components/dropdown";
  import GearIcon from "phosphor-svelte/lib/GearIcon";
  import SignOutIcon from "phosphor-svelte/lib/SignOutIcon";
  import UserIcon from "phosphor-svelte/lib/UserIcon";
</script>

{#snippet userIcon()}
  <UserIcon size={16} />
{/snippet}

{#snippet gearIcon()}
  <GearIcon size={16} />
{/snippet}

{#snippet signOutIcon()}
  <SignOutIcon size={16} />
{/snippet}

<DropdownMenu.Root>
  <DropdownMenu.Trigger>
    {#snippet child({ props })}
      <button {...props} type="button" class="rounded-full">
        <span class="flex h-8 w-8 items-center justify-center rounded-full bg-kumo-brand text-sm font-medium text-white">
          MR
        </span>
      </button>
    {/snippet}
  </DropdownMenu.Trigger>
  <DropdownMenu.Content>
    <DropdownMenu.Item icon={userIcon}>Profile</DropdownMenu.Item>
    <DropdownMenu.Item icon={gearIcon}>Settings</DropdownMenu.Item>
    <DropdownMenu.Separator />
    <DropdownMenu.Item icon={signOutIcon} variant="danger">Log out</DropdownMenu.Item>
  </DropdownMenu.Content>
</DropdownMenu.Root>

Navigation Links

Use DropdownMenu.LinkItem for menu items that navigate to a URL. This renders a semantic <a> element with full control over link attributes like target and rel.

<script lang="ts">
  import { Button } from "kumo-svelte/components/button";
  import * as DropdownMenu from "kumo-svelte/components/dropdown";
  import ArrowSquareOutIcon from "phosphor-svelte/lib/ArrowSquareOutIcon";
  import BookOpenIcon from "phosphor-svelte/lib/BookOpenIcon";
  import GearIcon from "phosphor-svelte/lib/GearIcon";
</script>

{#snippet gearIcon()}
  <GearIcon size={16} />
{/snippet}

{#snippet bookIcon()}
  <BookOpenIcon size={16} />
{/snippet}

{#snippet externalIcon()}
  <ArrowSquareOutIcon size={16} />
{/snippet}

<DropdownMenu.Root>
  <DropdownMenu.Trigger>
    {#snippet child({ props })}
      <Button {...props}>Resources</Button>
    {/snippet}
  </DropdownMenu.Trigger>
  <DropdownMenu.Content>
    <DropdownMenu.LinkItem href="/settings" icon={gearIcon}>Settings</DropdownMenu.LinkItem>
    <DropdownMenu.LinkItem href="/docs" icon={bookIcon}>Documentation</DropdownMenu.LinkItem>
    <DropdownMenu.Separator />
    <DropdownMenu.LinkItem href="https://developers.cloudflare.com" target="_blank" icon={externalIcon}>
      Developer Docs
    </DropdownMenu.LinkItem>
  </DropdownMenu.Content>
</DropdownMenu.Root>

API Reference

DropdownMenu

PropTypeDefault
childrenSnippet—
dir"ltr" | "rtl"—
onOpenChange(open: boolean) => void—
onOpenChangeComplete(open: boolean) => void—
openbooleanfalse

DropdownMenu.CheckboxGroup

No component-specific props. This component accepts child content or standard forwarded attributes.

DropdownMenu.CheckboxItem

PropTypeDefault
childrenSnippet—

DropdownMenu.Content

PropTypeDefault
containerPortalProps["to"]—

DropdownMenu.Group

No component-specific props. This component accepts child content or standard forwarded attributes.

DropdownMenu.Item

PropTypeDefault
childrenSnippet—
iconSnippet—
insetbooleanfalse
selectedbooleanfalse
variantKumoDropdownVariantKUMO_DROPDOWN_DEFAULT_VARIANTS.variant

DropdownMenu.Label

PropTypeDefault
insetbooleanfalse

DropdownMenu.LinkItem

PropTypeDefault
childrenSnippet—
iconSnippet—
insetbooleanfalse
variantKumoDropdownVariantKUMO_DROPDOWN_DEFAULT_VARIANTS.variant

DropdownMenu.Portal

PropTypeDefault
childrenSnippet—
toPortalProps["to"]—

DropdownMenu.RadioGroup

No component-specific props. This component accepts child content or standard forwarded attributes.

DropdownMenu.RadioItem

PropTypeDefault
childrenSnippet<[checked: boolean]>—
iconSnippet—
insetbooleanfalse

DropdownMenu.Separator

No component-specific props. This component accepts child content or standard forwarded attributes.

DropdownMenu.Shortcut

PropTypeDefault
childrenSnippet—

DropdownMenu.Sub

No component-specific props. This component accepts child content or standard forwarded attributes.

DropdownMenu.SubContent

No component-specific props. This component accepts child content or standard forwarded attributes.

DropdownMenu.SubTrigger

PropTypeDefault
childrenSnippet—
iconSnippet—
insetbooleanfalse

DropdownMenu.Trigger

No component-specific props. This component accepts child content or standard forwarded attributes.

On this page

  • Import
  • Usage
  • Examples
    • Basic Dropdown
    • Inset Items
    • Handling Item Clicks
    • Checkbox Items
    • Nested Menu with Radio Selection
    • Custom Trigger with Avatar
    • Navigation Links
  • API Reference
    • DropdownMenu
    • DropdownMenu.CheckboxGroup
    • DropdownMenu.CheckboxItem
    • DropdownMenu.Content
    • DropdownMenu.Group
    • DropdownMenu.Item
    • DropdownMenu.Label
    • DropdownMenu.LinkItem
    • DropdownMenu.Portal
    • DropdownMenu.RadioGroup
    • DropdownMenu.RadioItem
    • DropdownMenu.Separator
    • DropdownMenu.Shortcut
    • DropdownMenu.Sub
    • DropdownMenu.SubContent
    • DropdownMenu.SubTrigger
    • DropdownMenu.Trigger