DocsComponentsMenubar
Menubar
A desktop-style menu bar: File, Edit, View...
Alpine.js8 files
<pb-ui.menubar>
<pb-ui.menubar-menu>
<pb-ui.menubar-trigger>File</pb-ui.menubar-trigger>
<pb-ui.menubar-content>
<pb-ui.menubar-item>New tab <pb-ui.menubar-shortcut>⌘T</pb-ui.menubar-shortcut></pb-ui.menubar-item>
<pb-ui.menubar-item>New window <pb-ui.menubar-shortcut>⌘N</pb-ui.menubar-shortcut></pb-ui.menubar-item>
<pb-ui.menubar-separator />
<pb-ui.menubar-item>Print… <pb-ui.menubar-shortcut>⌘P</pb-ui.menubar-shortcut></pb-ui.menubar-item>
</pb-ui.menubar-content>
</pb-ui.menubar-menu>
<pb-ui.menubar-menu>
<pb-ui.menubar-trigger>Edit</pb-ui.menubar-trigger>
<pb-ui.menubar-content>
<pb-ui.menubar-item>Cancel <pb-ui.menubar-shortcut>⌘Z</pb-ui.menubar-shortcut></pb-ui.menubar-item>
<pb-ui.menubar-item>Redo <pb-ui.menubar-shortcut>⇧⌘Z</pb-ui.menubar-shortcut></pb-ui.menubar-item>
<pb-ui.menubar-separator />
<pb-ui.menubar-item>Cut</pb-ui.menubar-item>
<pb-ui.menubar-item>Copy</pb-ui.menubar-item>
<pb-ui.menubar-item>Paste</pb-ui.menubar-item>
</pb-ui.menubar-content>
</pb-ui.menubar-menu>
<pb-ui.menubar-menu>
<pb-ui.menubar-trigger>View</pb-ui.menubar-trigger>
<pb-ui.menubar-content>
<pb-ui.menubar-label>Appearance</pb-ui.menubar-label>
<pb-ui.menubar-item inset>Full screen</pb-ui.menubar-item>
<pb-ui.menubar-item inset>Hide sidebar</pb-ui.menubar-item>
</pb-ui.menubar-content>
</pb-ui.menubar-menu>
</pb-ui.menubar>Installation
pyblade-ui add menubar- Install the dependencies
Alpine.js, loaded in your
<head>. - Copy these files into your projectcomponents/ui/menubar.html
<div role="menubar" data-slot="menubar" x-data="{ active: null }" x-on:keydown.escape="active = null" x-on:click.outside="active = null" {{ attributes.cn("flex h-9 items-center gap-1 rounded-md border bg-background p-1 shadow-xs") }}>{{ slot }}</div>components/ui/menubar_menu.html@props({'value': ''}) <div data-slot="menubar-menu" x-data="{ value: '{{ value }}' || Math.random().toString(36).slice(2) }" {{ attributes.cn("relative") }}>{{ slot }}</div>components/ui/menubar_trigger.html<button type="button" role="menuitem" data-slot="menubar-trigger" x-on:click="active = active === value ? null : value" x-on:mouseenter="active && (active = value)" x-bind:aria-expanded="active === value" x-bind:data-state="active === value ? 'open' : 'closed'" {{ attributes.cn("flex cursor-pointer items-center rounded-sm px-2 py-1 text-sm font-medium outline-hidden select-none hover:bg-accent focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground") }}>{{ slot }}</button>components/ui/menubar_content.html<div role="menu" data-slot="menubar-content" x-show="active === value" x-cloak x-on:click="$event.target.closest('[data-slot=menubar-item]') && (active = null)" x-transition:enter="duration-100 ease-out" x-transition:enter-start="scale-95 opacity-0" x-transition:enter-end="scale-100 opacity-100" {{ attributes.cn("absolute top-full left-0 z-50 mt-2 min-w-[12rem] origin-top-left overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md") }}>{{ slot }}</div>components/ui/menubar_item.html@props({'href': None, 'variant': 'default', 'inset': False}) <a role="menuitem" data-slot="menubar-item" @if(href)href="{{ href }}"@endif tabindex="0" {{ attributes.cn( "relative flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground aria-disabled:pointer-events-none aria-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", {'default': '', 'destructive': 'text-destructive hover:bg-destructive/10 focus:bg-destructive/10 dark:hover:bg-destructive/20'}[variant], {'True': 'pl-8', 'False': ''}[str(bool(inset))], ) }}>{{ slot }}</a>components/ui/menubar_separator.html<div role="separator" data-slot="menubar-separator" {{ attributes.cn("-mx-1 my-1 h-px bg-border") }}></div>components/ui/menubar_label.html<div data-slot="menubar-label" {{ attributes.cn("px-2 py-1.5 text-sm font-medium") }}>{{ slot }}</div>components/ui/menubar_shortcut.html<span data-slot="menubar-shortcut" {{ attributes.cn("ml-auto text-xs tracking-widest text-muted-foreground") }}>{{ slot }}</span> - Update the path to fit your project
The
componentsfolder is the one set inpyblade.toml.
Usage
The tags <pb-ui.menubar> <pb-ui.menubar-menu> <pb-ui.menubar-trigger> <pb-ui.menubar-content> <pb-ui.menubar-item> <pb-ui.menubar-separator> <pb-ui.menubar-label> <pb-ui.menubar-shortcut> are available in all your templates.
<pb-ui.menubar>
<pb-ui.menubar-menu>
<pb-ui.menubar-trigger>File</pb-ui.menubar-trigger>
<pb-ui.menubar-content>
<pb-ui.menubar-item>New Tab <pb-ui.menubar-shortcut>⌘T</pb-ui.menubar-shortcut></pb-ui.menubar-item>
<pb-ui.menubar-separator />
<pb-ui.menubar-item>Print</pb-ui.menubar-item>
</pb-ui.menubar-content>
</pb-ui.menubar-menu>
</pb-ui.menubar>Props
<pb-ui.menubar-menu>
| Prop | Default |
|---|---|
| value | '' |
<pb-ui.menubar-item>
| Prop | Default |
|---|---|
| href | None |
| variant | 'default' |
| inset | False |
Any other attribute (class, id, x-on:click, hx-post…) is passed to the root element; your Tailwind classes win over the component's.