Normative · ARIA

Ruolo Widget

checkbox

Contrassegna un elemento come checkbox a due o tre stati. Utilizzare prima <input type="checkbox">; ricorrere a role="checkbox" soltanto quando non è possibile usare l'input nativo — ad esempio per costruire un controllo tri-stato che deve mostrare un valore misto.

Quando utilizzarlo

Utilizzare <input type="checkbox">. L’elemento nativo fornisce focus, attivazione con Space, la pseudo-classe :checked, l’invio del form e la proprietà JS indeterminate per il tri-stato. role="checkbox" esiste per due casi:

  • Si necessita di una checkbox tri-stato esposta come aria-checked="mixed" (un «seleziona tutto» che riflette lo stato dei figli).
  • Un design system distribuisce un componente checkbox personalizzato che non è possibile sostituire.

Se si implementa role="checkbox" su un elemento che non è un input, è necessario impostare aria-checked (attributo obbligatorio), gestire tabindex="0" e intercettare il tasto Space tramite keydown.

Contratto da tastiera e focus

Secondo il pattern APG checkbox:

  • Tab sposta il focus sulla checkbox.
  • Space alterna aria-checked tra "true" e "false" (e "mixed" per il tri-stato).
  • Enter NON attiva una checkbox — solo Space. (Anche gli input nativi ignorano Enter nella maggior parte dei browser.)

Il focus rimane sulla checkbox dopo l’attivazione.

Errori comuni

  • role="checkbox" senza l’attributo aria-checked impostato. Lo stato è obbligatorio dal momento in cui l’elemento è presente nel DOM.
  • Utilizzare aria-checked="true" solo come hook di classe — aggiornare l’aspetto visivo senza mai aggiornare l’attributo al click.
  • Checkbox personalizzate che rispondono al click ma non a Space.
  • Racchiudere un <input> nativo all’interno di un <div role="checkbox"> — la semantica duplicata confonde gli screen reader.
  • Controlli tri-stato in cui Space cicla tra false → true → mixed → false. L’APG specifica false → true → false; il valore mixed è impostato programmaticamente dalla pagina, non dall’utente.

Esempio

<!-- Preferito -->
<label>
  <input type="checkbox" name="terms" required>
  Accetto i termini e le condizioni
</label>

<!-- "Seleziona tutto" personalizzato tri-stato -->
<div
  role="checkbox"
  tabindex="0"
  aria-checked="mixed"
  aria-labelledby="selectAllLabel"
>
</div>
<span id="selectAllLabel">Seleziona tutte le righe</span>