Cos'è ARIA?

ARIA (Accessible Rich Internet Applications) è una specifica W3C che consente di migliorare l'accessibilità delle applicazioni web ricche e dei componenti dinamici.

🏷️ Ruoli

Definiscono cosa è un elemento (button, navigation, alert...)

role="button"

📊 Stati

Descrivono lo stato corrente di un elemento (checked, expanded, disabled...)

aria-expanded="true"

🔧 Proprietà

Forniscono informazioni aggiuntive (label, describedby, controls...)

aria-label="Menu principale"

⚠️ Regola d'oro ARIA

Non usare ARIA se puoi usare HTML nativo

Moduli con attributi ARIA

Esempio negativo

Modulo senza ARIA

❌ Modulo inaccessibile senza attributi ARIA appropriati:

<!-- Negativo: nessuna etichetta, nessuna descrizione -->
<input type="text" placeholder="La tua email">

<!-- Negativo: icona non accessibile -->
<button>
  <span class="icon">🔍</span>
</button>

<!-- Negativo: errore non associato, nessun autocompletamento -->
<input type="password">
<div class="error">Password troppo corta</div>
Password troppo corta
Accetto i termini di utilizzo

Esempio positivo

Modulo con ARIA

✅ Modulo accessibile con attributi ARIA appropriati:

<!-- Positivo: aria-label per campo senza etichetta visibile -->
<input
  type="text"
  aria-label="Indirizzo email (obbligatorio)"
  aria-describedby="email-desc"
  aria-required="true">
<span id="email-desc">Formato: nome@esempio.com</span>

<!-- Positivo: pulsante con aria-label -->
<button aria-label="Invia modulo">
  <span aria-hidden="true">🔍</span>
</button>

<!-- Positivo: errore associato con aria-describedby -->
<input
  type="password"
  aria-label="Password (minimo 8 caratteri)"
  aria-invalid="true"
  aria-describedby="pwd-error"
  autocomplete="new-password">
<div id="pwd-error" role="alert">
  La password deve contenere almeno 8 caratteri
</div>
Formato: nome@esempio.com
Minimo 8 caratteri con numeri e lettere
Opzioni di notifica
Ricevi aggiornamenti importanti via email
Ricevi avvisi urgenti via SMS
Attributi ARIA utilizzati:
  • aria-label: Fornisce un'etichetta accessibile
  • aria-describedby: Associa una descrizione dettagliata
  • aria-required: Indica un campo obbligatorio
  • aria-invalid: Segnala un campo non valido
  • aria-labelledby: Fa riferimento a un'etichetta esistente
  • role="alert": Annuncia immediatamente gli errori
  • aria-hidden: Nasconde elementi decorativi
  • aria-live: Annuncia cambiamenti dinamici

Spiegazione: Gli attributi ARIA arricchiscono i moduli fornendo etichette, descrizioni e stati alle tecnologie assistive.

Accordion accessibile

Esempio negativo

Senza attributi ARIA

Cos'è l'accessibilità web?+
Perché è importante?+
Come iniziare?+
<!-- Negativo: Nessun attributo ARIA, nessuna navigazione da tastiera -->
<div class="accordion-header" @click="toggle">
  <span>Title</span>
  <span>+</span>
</div>
<div v-if="open">
  Content
</div>

Esempio positivo

Con ARIA appropriato

<!-- Positivo: ARIA completo con navigazione da tastiera -->
<button
  id="accordion-button-1"
  aria-expanded="false"
  aria-controls="panel-1"
  @click="toggle"
  @keydown.enter="toggle"
>
  Title
</button>
<div
  id="panel-1"
  role="region"
  aria-labelledby="accordion-button-1"
  :hidden="!open"
>
  Content
</div>

Spiegazione: Un accordion deve utilizzare gli attributi ARIA appropriati, supportare la navigazione da tastiera e annunciare i cambiamenti di stato.

Tabindex e navigazione da tastiera

L'attributo tabindex controlla se un elemento può ricevere il focus da tastiera e in quale ordine.

✅ tabindex="0"

L'elemento è focalizzabile nell'ordine naturale del DOM

tabindex="0"
<!-- Positivo: Elemento interattivo focalizzabile -->
<div role="button" aria-label="Custom action" tabindex="0">
  Custom button
</div>

⚠️ tabindex="-1"

Focalizzabile tramite JavaScript ma non tramite Tab

tabindex="-1"
<!-- Positivo: Per focus programmatico -->
<div role="alert" aria-live="assertive" tabindex="-1">
  Error message
</div>

❌ tabindex > 0

Cambia l'ordine di navigazione (evita!)

tabindex="5"
<!-- Negativo: Rompe l'ordine naturale del tab -->
<button tabindex="3">Third</button>
<button tabindex="1">First</button>
<button tabindex="2">Second</button>

📋 Best practice per tabindex

  • Usa tabindex="0" per rendere focalizzabili elementi interattivi personalizzati
  • Usa tabindex="-1" per il focus programmatico (modal, alert)
  • MAI usare valori positivi - rispetta l'ordine del DOM
  • Gli elementi interattivi nativi (<button>, <a>, <input>) non necessitano di tabindex

🎯 Esempi interattivi

Testa la navigazione da tastiera (Tab/Shift+Tab) con questi elementi:

✅ Elementi focalizzabili

Link
Pulsante personalizzato (div)

❌ Elementi non focalizzabili

Testo semplice (div)
Testo inline (span)

Paragrafo

💡 Suggerimenti per il test

  • Usa Tab per navigare in avanti
  • Usa Shift + Tab per navigare indietro
  • Usa Spazio o Invio per attivare gli elementi
  • Osserva l'indicatore di focus (contorno blu)
  • Nota quali elementi possono o non possono ricevere il focus

Menu a discesa accessibile

Esempio negativo

Esempio positivo

Spiegazione: Un menu a discesa deve supportare la navigazione da tastiera, chiudersi con Escape e mantenere il focus appropriatamente.

Galleria di immagini accessibile

Esempio negativo

Esempio positivo

Spiegazione: Una galleria di immagini deve consentire la navigazione da tastiera e fornire descrizioni contestuali per ogni immagine. Il pattern ARIA tablist/tab/tabpanel è perfetto per questo caso d'uso.

Tabella ordinabile accessibile

Esempio negativo

Nome ↑Email Ruolo Stato
Alice Martinalice@example.comAdminAttivo
Bob Dupontbob@example.comUtenteInattivo
Charlie Leroycharlie@example.comModeratoreAttivo
Diana Moreaudiana@example.comUtenteSospeso

Esempio positivo

Alice Martinalice@example.comAdminAttivo
Bob Dupontbob@example.comUtenteInattivo
Charlie Leroycharlie@example.comModeratoreAttivo
Diana Moreaudiana@example.comUtenteSospeso
Clicca sulle intestazioni delle colonne per ordinare la tabella. Usa Tab per navigare tra i pulsanti di ordinamento.

Spiegazione: Una tabella ordinabile deve indicare lo stato di ordinamento corrente, consentire la navigazione da tastiera e annunciare i cambiamenti agli screen reader.

Regioni dinamiche aria-live

Esempio negativo

Senza aria-live

I cambiamenti non vengono annunciati

<!-- Mauvais : pas d'attribut aria-live -->
<div class="status-banner">
  <p></p>
</div>

Contatore: 0

Problemi:

  • I cambiamenti non vengono annunciati
  • Gli utenti di screen reader non sanno che il contenuto è cambiato
  • Nessuna indicazione dell'importanza del messaggio

Esempio positivo

Con aria-live appropriato

I cambiamenti vengono annunciati in base alla loro priorità

<!-- Bon : avec aria-live="polite" pour informations -->
<div
  class="status-banner"
  aria-live="polite"
  aria-atomic="true"
  role="status"
>
  <p>Information : Données mises à jour</p>
</div>

<!-- Bon : avec aria-live="assertive" pour alertes -->
<div
  class="alert-banner"
  aria-live="assertive"
  aria-atomic="true"
  role="alert"
>
  <p>Attention : Action requise immédiatement</p>
</div>

Zona polite (informazioni)

Vantaggi:

  • I messaggi importanti interrompono con aria-live="assertive"
  • I messaggi informativi attendono con aria-live="polite"
  • aria-atomic="true" annuncia l'intero contenuto della regione
  • I ruoli appropriati (status, alert) forniscono più contesto

Spiegazione: Le regioni aria-live consentono di annunciare i cambiamenti di contenuto agli screen reader. 'polite' attende la fine dell'annuncio corrente, 'assertive' interrompe immediatamente.

Pulsanti icona accessibili

Esempio negativo

Pulsanti senza descrizione

Questi pulsanti non hanno indicazione testuale:

Problemi:
  • Gli screen reader annunciano solo "pulsante"
  • Impossibile conoscere l'azione senza vedere l'icona
  • Le emoji possono essere interpretate male
  • Nessun tooltip al passaggio del mouse

Esempio positivo

Pulsanti accessibili

Diversi approcci per rendere accessibili le icone:

1. Con aria-label
2. Con testo visibile
3. Con testo visivamente nascosto
Best practice:
  • Fornisci sempre testo alternativo (aria-label, testo nascosto o testo visibile)
  • Usa aria-hidden="true" sulle icone decorative
  • Aggiungi tooltip con l'attributo title
  • Preferisci il testo visibile quando lo spazio lo consente

Spiegazione: I pulsanti che contengono solo icone devono avere un aria-label o testo visivamente nascosto per essere compresi dagli screen reader.

Combobox / Ricerca con suggerimenti

Esempio negativo

Senza ARIA o navigazione da tastiera

Esempio positivo

Con ARIA e navigazione da tastiera

0 risultato/i disponibile/i

Spiegazione: Una ricerca con suggerimenti (combobox) deve essere navigabile da tastiera, annunciare i risultati e consentire la selezione.

Notifiche toast (Live Regions)

Esempio negativo

Senza aria-live

❌ Le notifiche non vengono annunciate agli screen reader

<!-- Negativo: non annunciato agli screen reader -->
<div v-if="showToast" class="toast">
  Votre demande a été enregistrée
</div>

Esempio positivo

Con aria-live appropriato

✅ Le notifiche vengono annunciate correttamente

<!-- Positivo: notifica info (polite) -->
<div
  v-if="showToast"
  role="status"
  aria-live="polite"
  aria-atomic="true"
  class="toast"
>
  <p>Votre demande a été enregistrée</p>
  <button @click="dismiss" aria-label="Fermer notification">✕</button>
</div>

<!-- Positivo: avviso errore (assertive) -->
<div
  v-if="showError"
  role="alert"
  aria-live="assertive"
  aria-atomic="true"
  class="toast error"
>
  <p>Erreur : action impossible à exécuter</p>
  <button @click="dismiss" aria-label="Fermer alerte">✕</button>
</div>
Differenze:
  • role="status" + aria-live="polite": Per notifiche informative, non interrompe la lettura corrente
  • role="alert" + aria-live="assertive": Per errori critici, interrompe immediatamente
  • aria-atomic="true": Annuncia l'intero contenuto della notifica

Spiegazione: Le notifiche dinamiche devono essere annunciate agli screen reader senza rubare il focus. Usa role='status' per le info e role='alert' per gli errori.