Menubar
Horizontal bar of root menus on the Popover API, with arrow-key travel between open menus.
INSTALL
1pnpm dlx @sayagodev/mo add menubarOr import the files from the package (no copy):
1import "@sayagodev/mo/css/menubar.css";2import "@sayagodev/mo/css/shared.css";3import "@sayagodev/mo/js/menubar.js";
EXAMPLES
Demo
1<mo-menubar>2 <button type="button" role="menuitem" popovertarget="mb-demo-file">File</button>3 <menu popover id="mb-demo-file">4 <button role="menuitem" type="button">5 New Tab6 <span data-shortcut>⌘T</span>7 </button>8 <button role="menuitem" type="button">9 New Window10 <span data-shortcut>⌘N</span>11 </button>12 <button role="menuitem" type="button" disabled>New Incognito Window</button>13 <hr />14 <button role="menuitem" type="button" popovertarget="mb-demo-share">Share</button>15 <menu popover id="mb-demo-share">16 <button role="menuitem" type="button">Email link</button>17 <button role="menuitem" type="button">Messages</button>18 <button role="menuitem" type="button">Notes</button>19 </menu>20 <hr />21 <button role="menuitem" type="button">22 Print…23 <span data-shortcut>⌘P</span>24 </button>25 </menu>26 27 <button type="button" role="menuitem" popovertarget="mb-demo-edit">Edit</button>28 <menu popover id="mb-demo-edit">29 <button role="menuitem" type="button">30 Undo31 <span data-shortcut>⌘Z</span>32 </button>33 <button role="menuitem" type="button">34 Redo35 <span data-shortcut>⇧⌘Z</span>36 </button>37 <hr />38 <button role="menuitem" type="button" popovertarget="mb-demo-find">Find</button>39 <menu popover id="mb-demo-find">40 <button role="menuitem" type="button">Search the web</button>41 <hr />42 <button role="menuitem" type="button">Find…</button>43 <button role="menuitem" type="button">Find Next</button>44 <button role="menuitem" type="button">Find Previous</button>45 </menu>46 <hr />47 <button role="menuitem" type="button">Cut</button>48 <button role="menuitem" type="button">Copy</button>49 <button role="menuitem" type="button">Paste</button>50 </menu>51 52 <button type="button" role="menuitem" popovertarget="mb-demo-view">View</button>53 <menu popover id="mb-demo-view">54 <button role="menuitemcheckbox" type="button" aria-checked="false">55 Always Show Bookmarks Bar56 </button>57 <button role="menuitemcheckbox" type="button" aria-checked="true">58 Always Show Full URLs59 </button>60 <hr />61 <button role="menuitem" type="button" data-inset>62 Reload63 <span data-shortcut>⌘R</span>64 </button>65 <button role="menuitem" type="button" disabled data-inset>66 Force Reload67 <span data-shortcut>⇧⌘R</span>68 </button>69 <hr />70 <button role="menuitem" type="button" data-inset>Toggle Fullscreen</button>71 <hr />72 <button role="menuitem" type="button" data-inset>Hide Sidebar</button>73 </menu>74 75 <button type="button" role="menuitem" popovertarget="mb-demo-profiles">Profiles</button>76 <menu popover id="mb-demo-profiles">77 <button role="menuitemradio" type="button" aria-checked="false">Andy</button>78 <button role="menuitemradio" type="button" aria-checked="true">Benoit</button>79 <button role="menuitemradio" type="button" aria-checked="false">Luis</button>80 <hr />81 <button role="menuitem" type="button" data-inset>Edit…</button>82 <hr />83 <button role="menuitem" type="button" data-inset>Add Profile…</button>84 </menu>85</mo-menubar>86
Checkboxes
1<mo-menubar>2 <button type="button" role="menuitem" popovertarget="mb-check-view">View</button>3 <menu popover id="mb-check-view">4 <button role="menuitemcheckbox" type="button" aria-checked="false">5 Always Show Bookmarks Bar6 </button>7 <button role="menuitemcheckbox" type="button" aria-checked="true">8 Always Show Full URLs9 </button>10 <hr />11 <button role="menuitem" type="button" data-inset>12 Reload13 <span data-shortcut>⌘R</span>14 </button>15 <button role="menuitem" type="button" disabled data-inset>16 Force Reload17 <span data-shortcut>⇧⌘R</span>18 </button>19 </menu>20 21 <button type="button" role="menuitem" popovertarget="mb-check-format">Format</button>22 <menu popover id="mb-check-format">23 <button role="menuitemcheckbox" type="button" aria-checked="true">24 Strikethrough25 </button>26 <button role="menuitemcheckbox" type="button" aria-checked="false">27 Code28 </button>29 <button role="menuitemcheckbox" type="button" aria-checked="false">30 Superscript31 </button>32 </menu>33</mo-menubar>34
Radio groups
1<mo-menubar>2 <button type="button" role="menuitem" popovertarget="mb-radio-profiles">Profiles</button>3 <menu popover id="mb-radio-profiles">4 <button role="menuitemradio" type="button" aria-checked="false">Andy</button>5 <button role="menuitemradio" type="button" aria-checked="true">Benoit</button>6 <button role="menuitemradio" type="button" aria-checked="false">Luis</button>7 <hr />8 <button role="menuitem" type="button" data-inset>Edit…</button>9 <button role="menuitem" type="button" data-inset>Add Profile…</button>10 </menu>11 12 <button type="button" role="menuitem" popovertarget="mb-radio-theme">Theme</button>13 <menu popover id="mb-radio-theme">14 <button role="menuitemradio" type="button" aria-checked="false">Light</button>15 <button role="menuitemradio" type="button" aria-checked="false">Dark</button>16 <button role="menuitemradio" type="button" aria-checked="true">System</button>17 </menu>18</mo-menubar>19
With icons
1<mo-menubar>2 <button type="button" role="menuitem" popovertarget="mb-icons-file">File</button>3 <menu popover id="mb-icons-file">4 <button role="menuitem" type="button">5 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z" /><path d="M14 2v4a2 2 0 0 0 2 2h4" /></svg>6 New File7 <span data-shortcut>⌘N</span>8 </button>9 <button role="menuitem" type="button">10 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z" /></svg>11 Open Folder12 </button>13 <hr />14 <button role="menuitem" type="button">15 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z" /><path d="M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7" /><path d="M7 3v4a1 1 0 0 0 1 1h7" /></svg>16 Save17 <span data-shortcut>⌘S</span>18 </button>19 </menu>20 21 <button type="button" role="menuitem" popovertarget="mb-icons-more">More</button>22 <menu popover id="mb-icons-more">23 <button role="menuitem" type="button">24 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z" /><circle cx="12" cy="12" r="3" /></svg>25 Settings26 </button>27 <button role="menuitem" type="button">28 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="10" /><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3" /><path d="M12 17h.01" /></svg>29 Help30 </button>31 <hr />32 <button role="menuitem" type="button" data-variant="danger">33 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 6h18" /><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" /><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" /></svg>34 Delete35 </button>36 </menu>37</mo-menubar>38
Submenu
1<mo-menubar>2 <button type="button" role="menuitem" popovertarget="mb-submenu-file">File</button>3 <menu popover id="mb-submenu-file">4 <button role="menuitem" type="button" popovertarget="mb-submenu-share">Share</button>5 <menu popover id="mb-submenu-share">6 <button role="menuitem" type="button">Email link</button>7 <button role="menuitem" type="button">Messages</button>8 <button role="menuitem" type="button">Notes</button>9 </menu>10 <hr />11 <button role="menuitem" type="button">12 Print...13 <span data-shortcut>⌘P</span>14 </button>15 </menu>16 17 <button type="button" role="menuitem" popovertarget="mb-submenu-edit">Edit</button>18 <menu popover id="mb-submenu-edit">19 <button role="menuitem" type="button">20 Undo21 <span data-shortcut>⌘Z</span>22 </button>23 <button role="menuitem" type="button">24 Redo25 <span data-shortcut>⇧⌘Z</span>26 </button>27 <hr />28 <button role="menuitem" type="button" popovertarget="mb-submenu-find">Find</button>29 <menu popover id="mb-submenu-find">30 <button role="menuitem" type="button">Find...</button>31 <button role="menuitem" type="button">Find Next</button>32 <button role="menuitem" type="button">Find Previous</button>33 </menu>34 <hr />35 <button role="menuitem" type="button">Cut</button>36 <button role="menuitem" type="button">Copy</button>37 <button role="menuitem" type="button">Paste</button>38 </menu>39</mo-menubar>40
USAGE
1<mo-menubar>2 <button role="menuitem" popovertarget="m-file">File</button>3 <menu popover id="m-file">4 <button role="menuitem">Open <span data-shortcut>⌘O</span></button>5 <button role="menuitem" popovertarget="s-share">Share…</button>6 <menu popover id="s-share">7 <button role="menuitem">Email link</button>8 </menu>9 </menu>10</mo-menubar>
API
NAMEKINDDESCRIPTION
<mo-menubar>elementBar of root menus; full dropdown keyboard model per segment
> [popovertarget] + > menu[popover]attributeRoot trigger/surface pairs by id
[data-label] / [data-shortcut] / [data-inset]attributeHeading · key hint · alignment
--mo-menubar-height / -gaptokenBar height and spacing between triggers
--mo-menubar-min-width / -radiustokenOpen menu minimum width and corner radius
FILES
src/css/menubar.csssrc/css/shared.csssrc/js/menubar.jsInstall:
mo add menubarTHEMING · PLAYGROUND
This is the exact component from the examples above, wearing a completely different theme. Edit the tokens and --mo-* hooks in the editor — autocomplete knows them all — and the preview obeys in real time. Your CSS always wins.
Global tokens
--accent--accent-foreground--background--border--destructive--foreground--muted--muted-foreground--popover--popover-foreground--radius--ringComponent hooks
--mo-menubar-gap--mo-menubar-height--mo-menubar-min-width--mo-menubar-radiusPreview
Your CSS
Try it: type --mo- for the component hooks, or edit any value — the preview obeys in real time.