Context Menu
Right-click menu opening at the pointer with flip-on-overflow. Full dropdown item anatomy inside.
INSTALL
1pnpm dlx @sayagodev/mo add context-menuOr import the files from the package (no copy):
1import "@sayagodev/mo/css/context-menu.css";2import "@sayagodev/mo/js/context-menu.js";
Also copied as dependency: shared.css
EXAMPLES
Basic
Right click here
1<div data-context-menu data-variant="outline">2 Right click here3 <menu popover id="ctx-demo">4 <button role="menuitem" type="button">Back</button>5 <button role="menuitem" type="button" disabled>Forward</button>6 <button role="menuitem" type="button">Reload</button>7 </menu>8</div>9
Checkboxes
Right click here
1<div data-context-menu data-variant="outline">2 Right click here3 <menu popover id="ctx-checkboxes">4 <button role="menuitemcheckbox" type="button" aria-checked="true">5 Show Bookmarks Bar6 </button>7 <button role="menuitemcheckbox" type="button" aria-checked="false">8 Show Full URLs9 </button>10 <button role="menuitemcheckbox" type="button" aria-checked="true">11 Show Developer Tools12 </button>13 </menu>14</div>15
Radio groups
Right click here
1<div data-context-menu data-variant="outline">2 Right click here3 <menu popover id="ctx-radiogroup">4 <div role="group">5 <div data-label>People</div>6 <button role="menuitemradio" type="button" aria-checked="true">7 Pedro Duarte8 </button>9 <button role="menuitemradio" type="button" aria-checked="false">10 Colm Tuite11 </button>12 </div>13 <hr />14 <div role="group">15 <div data-label>Theme</div>16 <button role="menuitemradio" type="button" aria-checked="false">Light</button>17 <button role="menuitemradio" type="button" aria-checked="false">Dark</button>18 <button role="menuitemradio" type="button" aria-checked="false">System</button>19 </div>20 </menu>21</div>22
Shortcuts
Right click here
1<div data-context-menu data-variant="outline">2 Right click here3 <menu popover id="ctx-shortcuts">4 <button role="menuitem" type="button">5 Back6 <span data-shortcut>⌘[</span>7 </button>8 <button role="menuitem" type="button" disabled>9 Forward10 <span data-shortcut>⌘]</span>11 </button>12 <button role="menuitem" type="button">13 Reload14 <span data-shortcut>⌘R</span>15 </button>16 <hr />17 <button role="menuitem" type="button">18 Save19 <span data-shortcut>⌘S</span>20 </button>21 <button role="menuitem" type="button">22 Save As…23 <span data-shortcut>⇧⌘S</span>24 </button>25 </menu>26</div>27
With icons
Right click here
1<div data-context-menu data-variant="outline">2 Right click here3 <menu popover id="ctx-icons">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"><rect width="14" height="14" x="8" y="8" rx="2" ry="2" /><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" /></svg>6 Copy7 </button>8 <button role="menuitem" type="button">9 <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="6" cy="6" r="3" /><path d="M8.12 8.12 12 12" /><path d="M20 4 8.12 15.88" /><circle cx="6" cy="18" r="3" /><path d="M14.8 14.8 20 20" /></svg>10 Cut11 </button>12 <button role="menuitem" type="button">13 <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"><rect width="8" height="4" x="8" y="2" rx="1" ry="1" /><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2" /></svg>14 Paste15 </button>16 <hr />17 <button role="menuitem" type="button" data-variant="danger">18 <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 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6" /><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" /></svg>19 Delete20 </button>21 </menu>22</div>23
Groups
Right click here
1<div data-context-menu data-variant="outline">2 Right click here3 <menu popover id="ctx-groups">4 <div role="group">5 <div data-label>File</div>6 <button role="menuitem" type="button">New File <span data-shortcut>⌘N</span></button>7 <button role="menuitem" type="button">Open File <span data-shortcut>⌘O</span></button>8 <button role="menuitem" type="button">Save <span data-shortcut>⌘S</span></button>9 </div>10 <hr />11 <div role="group">12 <div data-label>Edit</div>13 <button role="menuitem" type="button">Undo <span data-shortcut>⌘Z</span></button>14 <button role="menuitem" type="button">Redo <span data-shortcut>⇧⌘Z</span></button>15 </div>16 <hr />17 <div role="group">18 <button role="menuitem" type="button">Cut <span data-shortcut>⌘X</span></button>19 <button role="menuitem" type="button">Copy <span data-shortcut>⌘C</span></button>20 <button role="menuitem" type="button">Paste <span data-shortcut>⌘V</span></button>21 </div>22 <hr />23 <div role="group">24 <button role="menuitem" type="button" data-variant="danger">Delete <span data-shortcut>⌫</span></button>25 </div>26 </menu>27</div>28
Destructive
Right click here
1<div data-context-menu data-variant="outline">2 Right click here3 <menu popover id="ctx-destructive">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="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z" /><path d="m15 5 4 4" /></svg>6 Edit7 </button>8 <button role="menuitem" type="button">9 <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="M4 12v8a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-8" /><polyline points="16 6 12 2 8 6" /><line x1="12" x2="12" y1="2" y2="15" /></svg>10 Share11 </button>12 <hr />13 <button role="menuitem" type="button" data-variant="danger">14 <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 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6" /><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" /></svg>15 Delete16 </button>17 </menu>18</div>19
Submenu
Right click here
1<div data-context-menu data-variant="outline">2 Right click here3 <menu popover id="ctx-submenu">4 <button role="menuitem" type="button">5 Copy6 <span data-shortcut>⌘C</span>7 </button>8 <button role="menuitem" type="button">9 Cut10 <span data-shortcut>⌘X</span>11 </button>12 <hr />13 <button role="menuitem" type="button" popovertarget="ctx-submenu-more">More Tools</button>14 <menu popover id="ctx-submenu-more">15 <button role="menuitem" type="button">Save Page...</button>16 <button role="menuitem" type="button">Create Shortcut...</button>17 <button role="menuitem" type="button">Name Window...</button>18 <hr />19 <button role="menuitem" type="button">Developer Tools</button>20 <hr />21 <button role="menuitem" type="button" data-variant="danger">Delete</button>22 </menu>23 </menu>24</div>25
Sides
Right click (top)
Right click (right)
Right click (bottom)
Right click (left)
1<div style="display:grid; gap:1rem; max-width:32rem;">2 <div data-context-menu data-variant="outline">3 Right click (top)4 <menu popover id="ctx-sides-top" data-side="top">5 <button role="menuitem" type="button">Back</button>6 <button role="menuitem" type="button">Forward</button>7 <button role="menuitem" type="button">Reload</button>8 </menu>9 </div>10 <div data-context-menu data-variant="outline">11 Right click (right)12 <menu popover id="ctx-sides-right" data-side="right">13 <button role="menuitem" type="button">Back</button>14 <button role="menuitem" type="button">Forward</button>15 <button role="menuitem" type="button">Reload</button>16 </menu>17 </div>18 <div data-context-menu data-variant="outline">19 Right click (bottom)20 <menu popover id="ctx-sides-bottom" data-side="bottom">21 <button role="menuitem" type="button">Back</button>22 <button role="menuitem" type="button">Forward</button>23 <button role="menuitem" type="button">Reload</button>24 </menu>25 </div>26 <div data-context-menu data-variant="outline">27 Right click (left)28 <menu popover id="ctx-sides-left" data-side="left">29 <button role="menuitem" type="button">Back</button>30 <button role="menuitem" type="button">Forward</button>31 <button role="menuitem" type="button">Reload</button>32 </menu>33 </div>34</div>35
USAGE
1<div data-context-menu>2 <p>Right-click anywhere in here.</p>3 <menu popover id="ctx-1">4 <div data-label>Paper</div>5 <button role="menuitemradio" aria-checked="true">A4</button>6 <hr />7 <button role="menuitem" popovertarget="sub1">More…</button>8 <menu popover id="sub1"><button role="menuitem">Duplicate</button></menu>9 </menu>10</div>
API
NAMEKINDDESCRIPTION
[data-context-menu]attributeContent region; right-click opens the menu at the pointer
menu[popover]elementSurface; nested popovertarget = side submenu
[role=menuitem*]attributeitem · checkbox · radio anatomy as dropdown
FILES
src/css/context-menu.csssrc/js/context-menu.jsdep: src/css/shared.cssInstall:
mo add context-menuTHEMING · 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--border--destructive--foreground--muted-foreground--popover--popover-foreground--radius--ringComponent hooks
--mo-context-menu-min-width--mo-context-menu-outline-color--mo-context-menu-outline-width--mo-context-menu-radiusPreview
Your CSS
Try it: type --mo- for the component hooks, or edit any value — the preview obeys in real time.