Tucano v0.37.2

Menu do botão direito

O menu de ações que aparece onde a pessoa clicou. É o mesmo menu suspenso — mesma marcação, mesmos itens, mesmo teclado —, só que aberto pelo botão direito e ancorado no ponto do clique. Numa lista, os itens costumam mudar conforme a linha: por isso items também aceita uma função.

Clique com o botão direito numa linha. Pelo teclado, chegue de Tab e aperte a tecla de menu ou Shift+F10.

ClienteVencimentoValor
Padaria Pão Quente12/09/202612400
Oficina Duas Rodas03/07/20263890.5
Marcenaria Horizonte28/11/2026760

Como usar

A área é quem escuta o botão direito; match diz qual pedaço dela é o alvo. O alvo vai para items, e é dele que saem as ações daquela linha.

new Tucano.ContextMenu('#contratos', {
  match: 'tbody tr',
  items: (row) => [
    { label: row.dataset.name },
    { text: 'Editar', shortcut: '⌘E', onClick: () => editar(row.dataset.id) },
    { text: 'Duplicar', onClick: () => duplicar(row.dataset.id) },
    { separator: true },
    { text: 'Excluir', variant: 'danger', onClick: () => excluir(row.dataset.id) },
  ],
});

Sem match, o alvo é a área inteira — o caminho para um cartão ou um painel com um menu só. Fora de um alvo, o menu do navegador continua aparecendo: um menu de ações que não sabe sobre o que age é pior que nenhum.

O menu do navegador continua a um Shift de distância

Shift + botão direito mostra o menu do próprio navegador, em qualquer lugar da área. Quem precisa de "abrir em nova aba", do corretor ortográfico ou de inspecionar a página não fica sem — e não há como tirar isso de alguém.

Exemplos

Área inteira, sem match

Um cartão com as mesmas ações em qualquer ponto dele.

Contrato 4821

Clique com o botão direito em qualquer lugar deste cartão.

Menu escrito no template

Quando é o servidor quem sabe o que a pessoa pode fazer, como no menu suspenso.

Nota fiscal 118

Botão direito aqui abre o menu do template.

<table id="contratos" data-tuc-contextmenu="#acoes-linha" data-match="tbody tr">
  {% for obj in page_obj %}
    <tr tabindex="0" data-id="{{ obj.pk }}">…</tr>
  {% endfor %}
</table>

<div class="tuc-dropdown" id="acoes-linha" hidden>
  <button type="button" class="tuc-dropdown__item">
    <span class="tuc-dropdown__text">Editar</span>
  </button>
</div>

Com o painel do template, os itens são os mesmos para toda linha: quem precisa saber qual foi clicada lê menu.target dentro do onclick, ou usa items como função.

Teclado e acessibilidade

O painel é o mesmo do menu suspenso: role="menu", itens como menuitem, foco dentro do menu e devolvido a quem o tinha antes. Aberto pelo botão direito, nenhum item nasce destacado — como no menu do sistema, a primeira seta é que destaca o primeiro. Aberto pelo teclado, o primeiro item já vem destacado, porque quem apertou a tecla de menu já quer andar pelos itens.

TeclaOndeAção
Tecla de menu, Shift+F10Alvo com focoAbre o menu ancorado no alvo
↑ ↓Menu abertoAnda pelos itens, dando a volta
Home EndMenu abertoPrimeiro e último item
Enter EspaçoItemEscolhe e fecha
EscMenu abertoFecha e devolve o foco
Shift + botão direitoÁreaDeixa passar o menu do navegador

O alvo precisa receber foco

A tecla de menu e o Shift+F10 abrem a partir de quem tem o foco. Numa tabela, ponha tabindex="0" nas linhas — sem isso, o que só existe no menu do botão direito fica inalcançável para quem não usa mouse. No celular, o toque longo abre o menu no Android; no iPhone, o Safari não avisa a página, então nenhuma ação pode existir só aqui.

API

Gerada do código a cada build — se algo não está aqui, não existe.

Marcação
[data-tuc-contextmenu]
Em JS
new Tucano.ContextMenu(alvo, opcoes)
Atributos
data-match data-placement data-tuc-contextmenu
Métodos
openAt close

Opções

OpçãoPadrãoPara quê
placement'bottom-start'
itemsnullarray como o do Dropdown, ou (alvo) => array
matchnullseletor do alvo dentro da area; sem ele, a area inteira
closeOnPicktrue
onOpennull(alvo, instancia) — para marcar a linha clicada, por exemplo
panelnullpainel ja escrito no template, no lugar de `items`