Normative · ARIA

Ruolo Widget composito

menu

Contrassegna un contenitore come menu applicativo — il popup dei menu in stile File/Modifica o i menu contestuali. Non esiste un equivalente HTML. La lista di navigazione di un sito NON è un menu; si utilizzi <nav> con <ul> di link.

Quando usarlo

Per un menu in stile applicativo — il popup che compare da un pulsante «File» o da un menu contestuale al clic destro, con navigazione tramite tasti freccia e chiusura con Escape. I figli devono avere role="menuitem", role="menuitemcheckbox", role="menuitemradio" o role="separator".

Il ruolo menu è una semantica da applicazione. L’errore più diffuso sul web è usare role="menu" per la navigazione del sito, il che intrappola gli utenti da tastiera nella navigazione con i tasti freccia, annuncia i link come voci di menu e rompe il modello mentale dell’utente.

Regola empirica: se il trigger è un collegamento ipertestuale e le voci sono collegamenti ipertestuali, si tratta di navigazione, non di un menu. Si utilizzi <nav> e <ul>.

Un menu DEVE avere un nome accessibile — si usi aria-label o aria-labelledby che punta al trigger.

Contratto tastiera + focus

Secondo il pattern menu APG:

  • Il pulsante trigger ha aria-haspopup="menu" e aria-expanded. L’attivazione del trigger apre il menu e sposta il focus sul primo menuitem.
  • All’interno del menu: i tasti freccia Su/Giù spostano il focus tra le voci; Home/Fine saltano alla prima/ultima.
  • Il tasto freccia Destra apre un sottomenu (se la voce attiva ne ha uno); il tasto freccia Sinistra torna al menu padre.
  • Invio o Spazio attivano la voce attiva e chiudono il menu.
  • Escape chiude il menu e restituisce il focus al trigger.
  • Typeahead: digitare una lettera salta alla voce successiva che inizia con quella lettera.

Singolo tab-stop: solo un menuitem alla volta ha tabindex="0"; gli altri hanno -1.

Errori comuni

  • role="menu" su un elemento <nav>. La semantica applicativa sovrascrive quella di navigazione — gli screen reader smettono di annunciarlo come landmark di navigazione.
  • Menu senza il corrispondente aria-haspopup="menu" sul trigger.
  • Escape chiude il menu ma non restituisce il focus al trigger, lasciando l’utente senza orientamento.
  • Il focus NON si sposta al primo menuitem all’apertura del menu — gli utenti devono premere Tab nel vuoto.
  • Sottomenu che si aprono solo al passaggio del mouse, non da tastiera.

Esempio

<button id="actions" aria-haspopup="menu" aria-expanded="false" aria-controls="actionsMenu">
  Azioni
</button>
<ul id="actionsMenu" role="menu" aria-labelledby="actions" hidden>
  <li role="menuitem" tabindex="0">Modifica</li>
  <li role="menuitem" tabindex="-1">Duplica</li>
  <li role="separator"></li>
  <li role="menuitem" tabindex="-1">Elimina</li>
</ul>