Right-click menu
The action menu that shows up where the person clicked. It is the same dropdown
menu — same markup, same items, same keyboard — only opened with the right button and anchored at the click
point. In a list the items usually change with the row, so items also takes a function.
Right-click a row. From the keyboard, Tab to a row and press the menu key or Shift+F10.
| Client | Due date | Amount |
|---|---|---|
| Padaria Pão Quente | 12/09/2026 | 12400 |
| Oficina Duas Rodas | 03/07/2026 | 3890.5 |
| Marcenaria Horizonte | 28/11/2026 | 760 |
How to use
The area listens for the right button; match says which part of it is the target. The
target goes to items, and that is where the actions for that row come from.
new Tucano.ContextMenu('#contracts', {
match: 'tbody tr',
items: (row) => [
{ label: row.dataset.name },
{ text: 'Edit', shortcut: '⌘E', onClick: () => edit(row.dataset.id) },
{ text: 'Duplicate', onClick: () => duplicate(row.dataset.id) },
{ separator: true },
{ text: 'Delete', variant: 'danger', onClick: () => remove(row.dataset.id) },
],
});Without match, the target is the whole area — the way to give a card or a panel a single menu. Outside
a target the browser's own menu still shows: an action menu that does not know what it acts on is worse than none.
The browser's menu stays one Shift away
Shift + right-click shows the browser's own menu, anywhere in the area. Whoever needs "open in new tab", the spell checker or the inspector is not left out — and that is not something to take from anyone.
Examples
Whole area, no match
A card with the same actions anywhere on it.
Contract 4821
Right-click anywhere on this card.
Menu written in the template
When the server is the one that knows what the person may do, as in the dropdown.
Invoice 118
Right-click here to open the template's menu.
<table id="contracts" data-tuc-contextmenu="#row-actions" data-match="tbody tr">
{% for obj in page_obj %}
<tr tabindex="0" data-id="{{ obj.pk }}">…</tr>
{% endfor %}
</table>
<div class="tuc-dropdown" id="row-actions" hidden>
<button type="button" class="tuc-dropdown__item">
<span class="tuc-dropdown__text">Edit</span>
</button>
</div>With the template panel the items are the same for every row: code that needs to know which one was clicked reads
menu.target inside the onclick, or uses items as a function.
Keyboard and accessibility
The panel is the dropdown's: role="menu", items as menuitem, focus inside the
menu and handed back to whoever had it. Opened with the right button, no item starts highlighted — like the system
menu, the first arrow key is what highlights the first one. Opened from the keyboard, the first item is already
highlighted, because whoever pressed the menu key wants to move through the items.
| Key | Where | Action |
|---|---|---|
Menu key, Shift+F10 | Focused target | Opens the menu anchored to the target |
↑ ↓ | Open menu | Moves through the items, wrapping around |
Home End | Open menu | First and last item |
Enter Space | Item | Picks it and closes |
Esc | Open menu | Closes and hands the focus back |
Shift + right-click | Area | Lets the browser's menu through |
The target has to be focusable
The menu key and Shift+F10 open from whatever has the focus. In a table, put tabindex="0" on the rows — without it, anything that lives only in the right-click menu is out of reach for people who do not use a mouse. On phones, a long press opens the menu on Android; on the iPhone, Safari does not tell the page, so no action can live only here.
API
Generated from the code on every build — if something is not here, it does not exist.
[data-tuc-contextmenu]new Tucano.ContextMenu(alvo, opcoes)data-match data-placement data-tuc-contextmenuopenAt closeOptions
The notes in this table come from comments in the source code, which are written in Portuguese.
| Option | Default | What for |
|---|---|---|
placement | 'bottom-start' | |
items | null | array como o do Dropdown, ou (alvo) => array |
match | null | seletor do alvo dentro da area; sem ele, a area inteira |
closeOnPick | true | |
onOpen | null | (alvo, instancia) — para marcar a linha clicada, por exemplo |
panel | null | painel ja escrito no template, no lugar de `items` |