Conlaccento

Un blog sul web making di Antonio Trifirò

Swatch WooCommerce e screen reader: i plugin non funzionano, così ne ho fatto uno accessibile


Immagina di voler comprare una maglietta su un negozio online. Devi scegliere la taglia e il colore. Se ci vedi e usi il mouse, ci metti due secondi: clic sul quadratino rosso, clic sulla taglia M, aggiungi al carrello. Ma prova a farlo senza mouse, solo con la tastiera. Oppure a occhi chiusi, ascoltando quello che ti legge uno screen reader.

Su moltissimi store WooCommerce, a quel punto, ti fermi. Quei quadratini colorati — gli swatch delle varianti — spesso non si raggiungono con il tasto Tab, non si selezionano con le frecce, e uno screen reader non ti dice nemmeno che esistono. È un pezzo piccolissimo di interfaccia, ma è proprio il punto in cui si decide un acquisto: se non puoi scegliere la variante, non puoi comprare.

Ho voluto capire quanto fosse diffuso il problema. Così ho preso i plugin swatch più usati per WooCommerce e li ho testati uno per uno con la tastiera e con VoiceOver. Lo spoiler è nel titolo: nessuno funzionava davvero, e in questo post ti racconto cosa ho trovato e perché quasi tutti sbagliano allo stesso modo.

Perché adesso è anche un problema legale

C’è un motivo in più per parlarne proprio ora. Dal 28 giugno 2025 è in vigore in Italia l’European Accessibility Act (EAA), la normativa europea che impone requisiti di accessibilità a una serie di settori — e l’e-commerce è tra i più esposti. Lo standard tecnico di riferimento è WCAG 2.2 livello AA: le stesse Web Content Accessibility Guidelines che, dall’altra parte dell’oceano, vengono citate nelle cause ADA Title III contro i negozi online statunitensi.

Tradotto: uno store che vende in Europa dovrebbe essere accessibile, e il selettore delle varianti è uno dei componenti che più facilmente non lo è. Non è un tecnicismo per addetti ai lavori — è la porta d’ingresso all’acquisto.

Se sul tema “obbligo di accessibilità” vuoi un inquadramento più ampio, ne ho scritto a proposito del meccanismo di feedback che l’accessibilità richiede. Qui resto sul pezzo concreto: gli swatch.

La ricerca: cosa succede davvero con uno screen reader

Ho installato i principali plugin swatch su un’installazione WooCommerce di prova e li ho provati da tastiera e con VoiceOver su macOS, sulla pagina di un prodotto variabile. Non ho misurato opinioni: ho guardato il markup che generano e ho annotato il comportamento osservabile — cosa riceve il focus, cosa viene annunciato, cosa no.

Ti riporto i tre casi più rappresentativi, restando sui fatti verificabili (ognuno lo puoi riprodurre aprendo i DevTools o navigando con Tab).

GetWooPlugins

È quello arrivato più vicino alla promozione. La navigazione da tastiera in buona parte funziona, e le opzioni ricevono il focus. I due limiti che ho riscontrato:

  • Il controllo per azzerare la selezione — il “Clear” — è reso come <a href="#">. Uno screen reader lo annuncia come “link”, non come pulsante: la sua funzionalità è compiere una azione (non una navigazione), ma è comunicato con il ruolo sbagliato. È una discrepanza tra ruolo e funzione (WCAG 4.1.2).
  • Il nome accessibile delle opzioni è affidato all’attributo title, poco verboso e non sempre esposto in modo affidabile.
  • L’indicatore di focus visibile è demandato al tema: se il tema non lo disegna bene, sparisce (è il classico problema dell’outline: none).

ThemeHigh

Qui gli swatch sono <div> senza ruolo né tabindex. Il plugin ha aggiunto in una versione recente la navigazione con le frecce, ed è un miglioramento di usabilità; ma resta un intervento sul comportamento del mouse/tastiera, non sulla semantica: allo screen reader il <div> continua a non dire cosa è, se è selezionato, o se quell’opzione è esaurita.

YITH

Il pattern qui è una <select> nativa nascosta affiancata da una fila di <div> cliccabili. Il risultato osservato con VoiceOver è che le opzioni-<div> non vengono annunciate come controlli di scelta: la semantica utile è nella <select> nascosta, ma l’interazione visiva avviene sui <div>, che non la espongono.

Non sto dando pagelle, e questo è lo stato dell’arte al momento della scrittura di questo articolo: sono tutti plugin fatti da persone competenti, e sul piano visivo funzionano benissimo. Il punto è un altro, ed è strutturale.

Perché falliscono quasi tutti allo stesso modo

Il filo comune è uno solo: questi swatch sono costruiti con <div> + JavaScript. E un <div>, per il browser e per le tecnologie assistive, non è un controllo: non è raggiungibile da tastiera, non ha uno stato “selezionato”, non annuncia nulla.

Per farlo sembrare un controllo devi ricostruire a mano tutto quello che un elemento nativo ti darebbe gratis: tabindex per il focus, role="radio", aria-checked, la gestione delle frecce, degli stati, del gruppo. È l’ARIA “finta” — una simulazione. E ogni pezzo che dimentichi, o che il tema sovrascrive, è un buco.

<!-- L'approccio diffuso: un div che "finge" di essere un controllo -->
<div class="swatch" data-value="rosso" title="Rosso"></div>
<!-- Nessun focus da tastiera, nessuno stato, niente da annunciare.
     Per renderlo accessibile dovresti aggiungere a mano
     tabindex, role, aria-checked, la gestione delle frecce... -->

La via più robusta è non simulare niente e usare l’elemento che il web ha già per “scegli una opzione tra tante”: il radio button dentro un gruppo etichettato.

<!-- L'approccio semantico: il browser fa già tutto -->
<fieldset class="swatch-group">
  <legend>Colore</legend>

  <input type="radio" id="colore-rosso" name="attribute_colore" value="rosso">
  <label for="colore-rosso" style="--swatch-color: #c0392b;">
    <span class="visually-hidden">Rosso</span>
  </label>
</fieldset>

Con questo markup, la navigazione da tastiera (Tab per raggiungere il gruppo, frecce per scegliere), lo stato “selezionato” e il nome dell’opzione ci sono già, perché li fornisce il browser. Non c’è ARIA da mantenere, non c’è niente da simulare. Lo swatch colorato lo disegni sul <label> con la CSS; il nome resta leggibile allo screen reader in uno <span> nascosto visivamente.

Cosa ho costruito

Da questa ricerca è nato Accent-On Accessible Swatches for WooCommerce, il plugin che ho pubblicato — gratis — su WordPress.org. Sostituisce i menu a tendina delle varianti WooCommerce con swatch di colore, immagine o testo, ed è costruito esattamente sul principio di sopra: un <fieldset> di <input type="radio"> nativi.

Sotto il cofano c’è un dettaglio che mi piace: la <select> originale di WooCommerce resta nel DOM, nascosta. Non reimplemento la logica delle varianti (prezzi, immagini, disponibilità) — la lascio fare a WooCommerce e mi limito a sincronizzare la scelta del radio con quella select. Meno codice mio significa meno cose che si rompono.

Quello che ho aggiunto è tutto ciò che serve perché il componente passi un audit WCAG 2.2 AA formale:

  • Navigazione da tastiera nativa — Tab per arrivare al gruppo, frecce per scegliere, con un indicatore di focus sempre visibile fornito dal plugin (non lasciato al tema).
  • Annuncio di nome e stato — lo screen reader legge il nome della variante e se è selezionata.
  • Opzioni esaurite raggiungibili e annunciate — non le nascondo: restano navigabili e vengono annunciate come “esaurito”. Se una variante esiste, chi usa lo screen reader ha il diritto di saperlo.
  • aria-live per la disponibilità dinamica — quando scegli un attributo e alcune combinazioni diventano non disponibili, il cambiamento viene annunciato, senza ricaricare la pagina.
  • Controllo di reset accessibile — il “Clear” è un vero <button>, non un link: risponde a Invio e Spazio ed è annunciato come pulsante.
  • Bordo sempre visibile su ogni swatch colore, così le opzioni restano distinguibili anche su temi chiari o scuri (contrasto non testuale, 1.4.11).
  • Supporto Alto Contrasto / forced-colors — quando il sistema forza i colori, quello dello swatch viene preservato, perché lì il colore è l’informazione.
  • Tooltip accessibili che rivelano il nome della variante sull’hover e sul focus da tastiera, chiudibili con Escape (1.4.13).

Gli swatch non bastano

Rendere accessibili gli swatch non rende accessibile il tuo store, ça va sans dire. Gli swatch sono uno dei componenti WooCommerce che più comunemente falliscono un controllo di accessibilità, ma non l’unico: il carrello, il checkout, i filtri, i messaggi di errore hanno spesso i loro problemi.

Il modo giusto di leggere questo plugin non è “adesso sono a posto con l’EAA”. È: se gli swatch del tuo store non passano, è molto probabile che non passino nemmeno altri pezzi. Se vuoi, un buon punto di partenza è proprio testare il resto del percorso d’acquisto con la stessa lente: tastiera e screen reader.

Come capire se i tuoi swatch sono accessibili

Se gestisci uno store, questa è la checklist che puoi eseguire tu stesso, senza strumenti particolari — solo la tastiera e (dove puoi) uno screen reader:

  • Puoi raggiungere le opzioni con Tab e sceglierle con le frecce, senza toccare il mouse?
  • Uno screen reader annuncia il nome dell’opzione e il fatto che è selezionata?
  • Le opzioni esaurite restano raggiungibili e vengono annunciate come tali, invece di sparire in silenzio?
  • Il controllo per azzerare la selezione è un vero <button> (annunciato “pulsante”, operabile con Invio e Spazio)?
  • Gli swatch colore hanno un bordo visibile anche sul bianco e su un tema scuro?
  • Reggono la modalità Alto Contrasto, o diventano tutti uguali?

Se anche solo una risposta è “no”, quel pezzo del tuo store sta lasciando fuori qualcuno — e, dal giugno 2025, è anche un rischio di conformità.

Provalo (e scrivimi)

Accent-On Accessible Swatches for WooCommerce è gratuito e open source. Lo installi direttamente dalla bacheca di WordPress o da qui:

Scarica il plugin da WordPress.org

Il codice è su GitHub, se vuoi guardarci dentro, aprire una issue o contribuire: github.com/conlaccento/accent-on-accessible-swatches-for-woocommerce.

E se gestisci uno store WooCommerce e vuoi capire dove — al di là degli swatch — l’accessibilità si rompe davvero, scrivimi: partire dal percorso d’acquisto reale, tastiera e screen reader alla mano, è il modo più onesto che conosco per scoprirlo.

Peace&Love! ✌️