Menu
Accessible dropdown menu with keyboard navigation, typeahead, and zero visual opinion.
Basic Menu
Click or use arrow keys / Home / End / Space / Enter / typeahead.
Edit
Duplicate
Archive
Delete
<BitBhMenu class="relative inline-block">
<BitBhMenuButton class="inline-flex items-center gap-2 rounded-lg border border-zinc-300 bg-white px-3.5 py-2 text-sm font-medium cursor-pointer transition-colors hover:border-zinc-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 data-state-open:border-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<Template Context="b">
Options
<span class="@($"text-zinc-500 transition-transform duration-200 {(b.IsOpen ? "rotate-180" : "")}")">▾</span>
</Template>
</BitBhMenuButton>
<BitBhMenuItems class="absolute top-[calc(100%+0.25rem)] left-0 z-30 m-0 min-w-40 list-none rounded-lg border border-zinc-200 bg-white p-1 shadow-lg">
<BitBhMenuItem OnClick='@(() => Log("Edit"))' class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700 data-disabled:opacity-40 data-disabled:cursor-not-allowed" Label="Edit">Edit</BitBhMenuItem>
<BitBhMenuItem OnClick='@(() => Log("Duplicate"))' class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700 data-disabled:opacity-40 data-disabled:cursor-not-allowed" Label="Duplicate">Duplicate</BitBhMenuItem>
<BitBhMenuItem OnClick='@(() => Log("Archive"))' class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700 data-disabled:opacity-40 data-disabled:cursor-not-allowed" Label="Archive">Archive</BitBhMenuItem>
<BitBhMenuItem OnClick='@(() => Log("Delete"))' class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700 data-disabled:opacity-40 data-disabled:cursor-not-allowed" Label="Delete">Delete</BitBhMenuItem>
</BitBhMenuItems>
</BitBhMenu>
@code {
private string? lastAction;
private void Log(string action) => lastAction = action;
}Disabled Items
data-disabled: dims items; arrow keys and typeahead skip them.
Profile
Settings
Billing (unavailable)
Sign out
<BitBhMenuItems class="absolute top-[calc(100%+0.25rem)] left-0 z-30 m-0 min-w-40 list-none rounded-lg border border-zinc-200 bg-white p-1 shadow-lg">
<BitBhMenuItem OnClick='@(() => Log("Profile"))' class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700 data-disabled:opacity-40 data-disabled:cursor-not-allowed" Label="Profile">Profile</BitBhMenuItem>
<BitBhMenuItem OnClick='@(() => Log("Settings"))' class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700 data-disabled:opacity-40 data-disabled:cursor-not-allowed" Label="Settings">Settings</BitBhMenuItem>
<BitBhMenuItem OnClick='@(() => Log("Billing"))' class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700 data-disabled:opacity-40 data-disabled:cursor-not-allowed" Label="Billing" Disabled="true">Billing (unavailable)</BitBhMenuItem>
<BitBhMenuItem OnClick='@(() => Log("Sign out"))' class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700 data-disabled:opacity-40 data-disabled:cursor-not-allowed" Label="Sign out">Sign out</BitBhMenuItem>
</BitBhMenuItems>Rich item content
Items can contain anything; provide Label for typeahead.
📄
New file
Create a blank document
⌘N
📂
Open…
Browse for a file
⌘O
💾
Save
Save the current document
⌘S
📤
Export
Not available in this plan
<BitBhMenuItems class="absolute top-[calc(100%+0.25rem)] left-0 z-30 m-0 min-w-64 list-none rounded-lg border border-zinc-200 bg-white p-1 shadow-lg">
<BitBhMenuItem OnClick='@(() => Log("New file"))' class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700" Label="New file">
<span class="text-base flex-shrink-0">📄</span>
<span class="flex flex-1 flex-col leading-tight">
<strong class="text-sm">New file</strong>
<span class="text-xs text-zinc-500">Create a blank document</span>
</span>
<span class="ml-auto text-xs text-zinc-500">⌘N</span>
</BitBhMenuItem>
<BitBhMenuItem OnClick='@(() => Log("Open"))' class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700" Label="Open">
<span class="text-base flex-shrink-0">📂</span>
<span class="flex flex-1 flex-col leading-tight">
<strong class="text-sm">Open…</strong>
<span class="text-xs text-zinc-500">Browse for a file</span>
</span>
<span class="ml-auto text-xs text-zinc-500">⌘O</span>
</BitBhMenuItem>
<BitBhMenuItem OnClick='@(() => Log("Save"))' class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700" Label="Save">
<span class="text-base flex-shrink-0">💾</span>
<span class="flex flex-1 flex-col leading-tight">
<strong class="text-sm">Save</strong>
<span class="text-xs text-zinc-500">Save the current document</span>
</span>
<span class="ml-auto text-xs text-zinc-500">⌘S</span>
</BitBhMenuItem>
<BitBhMenuItem OnClick='@(() => Log("Export"))' class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700 data-disabled:opacity-40 data-disabled:cursor-not-allowed" Label="Export" Disabled="true">
<span class="text-base flex-shrink-0">📤</span>
<span class="flex flex-1 flex-col leading-tight">
<strong class="text-sm">Export</strong>
<span class="text-xs text-zinc-500">Not available in this plan</span>
</span>
</BitBhMenuItem>
</BitBhMenuItems>Sections and dividers
Group items with plain <li> dividers and headings.
Zoom in
Zoom out
Full screen
Documentation
Keyboard shortcuts
<BitBhMenuItems class="absolute top-[calc(100%+0.25rem)] left-0 z-30 m-0 min-w-40 list-none rounded-lg border border-zinc-200 bg-white p-1 shadow-lg">
<li class="px-2.5 pt-1.5 pb-0.5 text-xs font-semibold uppercase tracking-wider text-zinc-500" role="presentation">View</li>
<BitBhMenuItem OnClick='@(() => Log("Zoom in"))' class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700" Label="Zoom in">Zoom in</BitBhMenuItem>
<BitBhMenuItem OnClick='@(() => Log("Zoom out"))' class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700" Label="Zoom out">Zoom out</BitBhMenuItem>
<BitBhMenuItem OnClick='@(() => Log("Full screen"))' class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700" Label="Full screen">Full screen</BitBhMenuItem>
<li class="my-1 h-px bg-zinc-200" role="separator"></li>
<li class="px-2.5 pt-1.5 pb-0.5 text-xs font-semibold uppercase tracking-wider text-zinc-500" role="presentation">Help</li>
<BitBhMenuItem OnClick='@(() => Log("Documentation"))' class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700" Label="Documentation">Documentation</BitBhMenuItem>
<BitBhMenuItem OnClick='@(() => Log("Keyboard shortcuts"))' class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700" Label="Keyboard shortcuts">Keyboard shortcuts</BitBhMenuItem>
</BitBhMenuItems>Anchor Positioning
Anchor auto-positions and flips. --button-width matches trigger width.
Edit
Duplicate
Archive
Cut
Copy
Paste
Option A
Option B
Option C
<BitBhMenu class="relative inline-block">
<BitBhMenuButton class="inline-flex items-center gap-2 rounded-lg border border-zinc-300 bg-white px-3.5 py-2 text-sm font-medium cursor-pointer transition-colors hover:border-zinc-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 data-state-open:border-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<Template Context="b">
Bottom Start
<span class="@($"text-zinc-500 transition-transform duration-200 {(b.IsOpen ? "rotate-180" : "")}")">▾</span>
</Template>
</BitBhMenuButton>
<BitBhMenuItems Anchor="@(new BitBhAnchorOptions { To = "bottom start", Gap = 4 })"
class="z-[9999] m-0 min-w-40 list-none rounded-lg border border-zinc-200 bg-white p-1 shadow-lg">
<BitBhMenuItem OnClick='@(() => Log("Edit"))' Label="Edit"
class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700">Edit</BitBhMenuItem>
<BitBhMenuItem OnClick='@(() => Log("Duplicate"))' Label="Duplicate"
class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700">Duplicate</BitBhMenuItem>
<BitBhMenuItem OnClick='@(() => Log("Archive"))' Label="Archive"
class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700">Archive</BitBhMenuItem>
</BitBhMenuItems>
</BitBhMenu>
@* Match-width: BitBhMenuItems exposes --button-width which can be used in arbitrary values: *@
<BitBhMenuItems Anchor="@(new BitBhAnchorOptions { To = "bottom", Gap = 4 })"
class="z-[9999] m-0 min-w-0 w-[var(--button-width)] list-none rounded-lg border border-zinc-200 bg-white p-1 shadow-lg">
<BitBhMenuItem OnClick='@(() => Log("Option A"))' Label="Option A"
class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700">Option A</BitBhMenuItem>
<BitBhMenuItem OnClick='@(() => Log("Option B"))' Label="Option B"
class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700">Option B</BitBhMenuItem>
<BitBhMenuItem OnClick='@(() => Log("Option C"))' Label="Option C"
class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700">Option C</BitBhMenuItem>
</BitBhMenuItems>Polymorphic items
Set As="a" for navigation links.
<BitBhMenu class="relative inline-block">
<BitBhMenuButton class="inline-flex items-center gap-2 rounded-lg border border-zinc-300 bg-white px-3.5 py-2 text-sm font-medium cursor-pointer transition-colors hover:border-zinc-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-600 data-state-open:border-blue-600 data-disabled:opacity-50 data-disabled:cursor-not-allowed">
<Template Context="b">
Navigate
<span class="@($"text-zinc-500 transition-transform duration-200 {(b.IsOpen ? "rotate-180" : "")}")">▾</span>
</Template>
</BitBhMenuButton>
<BitBhMenuItems class="absolute top-[calc(100%+0.25rem)] left-0 z-30 m-0 min-w-40 list-none rounded-lg border border-zinc-200 bg-white p-1 shadow-lg">
<BitBhMenuItem As="a" href="tw/button" Label="Button" class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700">Button</BitBhMenuItem>
<BitBhMenuItem As="a" href="tw/switch" Label="Switch" class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700">Switch</BitBhMenuItem>
<BitBhMenuItem As="a" href="tw/disclosure" Label="Disclosure" class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700">Disclosure</BitBhMenuItem>
<BitBhMenuItem As="a" href="tw/accordion" Label="Accordion" class="flex items-center gap-2 rounded-md px-2.5 py-2 text-sm cursor-pointer text-zinc-900 list-none no-underline data-active:bg-blue-50 data-active:text-blue-700">Accordion</BitBhMenuItem>
</BitBhMenuItems>
</BitBhMenu>