Data di pubblicazione: 5 marzo 2026
L'attributo HTML focusgroup è un modo dichiarativo proposto per aggiungere la navigazione con i tasti freccia della tastiera a widget compositi come barre degli strumenti, elenchi di schede, menu, caselle di riepilogo e così via senza scrivere codice JavaScript roving-tabindex. Un attributo
sostituisce centinaia di righe di boilerplate. Vorremmo ricevere il tuo feedback prima che questa
funzionalità venga implementata.
Provalo e inviaci il tuo feedback.
Puoi provare focusgroup oggi in Chrome, Edge e altri browser Chromium attivandolo in due modi:
- Test locale:nel browser, apri la pagina
about://flagse attiva il flag Funzionalità sperimentali della piattaforma web. In alternativa, avvia il browser dalla riga di comando utilizzando il parametro della riga di comando--enable-blink-features=Focusgroup. - Prova dell'origine:registrati alla prova dell'origine focusgroup per testarla sul tuo sito con utenti reali.
Poi esplora le demo interattive per vedere ogni pattern in azione.
Abbiamo bisogno del tuo contributo. Invia un problema del focus group per farci sapere cosa ne pensi.
Si tratta di un impegno cross-browser:la proposta proviene da Microsoft tramite l'OpenUI Community Group con un forte supporto da parte di Google. La forma dell'API potrebbe cambiare in base al tuo feedback. Vediamo nel dettaglio il problema che risolve focusgroup e come funziona l'API.
Il problema: roving tabindex manuale
Se hai mai creato una barra degli strumenti, un elenco di schede, un menu o una casella elenco, hai scritto una versione di questo codice. La guida alle pratiche di creazione ARIA (ARIA Authoring Practices Guide, APG) consiglia che i widget compositi presentino un unico punto di tabulazione e consentano agli utenti di spostarsi tra gli elementi con i tasti freccia. Questo pattern è noto come "indice di tabulazione mobile". Molti framework UI lo reimplementano da zero:
<div role="toolbar" aria-label="Text formatting" id="toolbar">
<button type="button" tabindex="0">Bold</button>
<button type="button" tabindex="-1">Italic</button>
<button type="button" tabindex="-1">Underline</button>
<button type="button" tabindex="-1">Strikethrough</button>
</div>
Da qui, gli sviluppatori devono utilizzare JavaScript che rileva i tasti freccia per spostare lo stato attivo e regolare l'attributo tabindex per tutti gli elementi. Questa è la versione semplificata. Un'implementazione di produzione deve anche gestire:
- Modalità di scrittura e da destra a sinistra:regola la direzione dei tasti freccia in base alla direzione dei contenuti.
- Memoria dell'ultimo elemento attivo: ripristina lo stato attivo dell'elemento attivo in precedenza quando un utente torna alle schede.
- Elementi disattivati e nascosti: vengono ignorati durante la navigazione.
- Elementi dinamici:aggiorna l'indice mobile quando vengono aggiunti o rimossi elementi.
La maggior parte delle librerie UI, tra cui React, Angular CDK e Fluent UI, include la propria versione di questa logica. Si tratta di un grande sforzo duplicato per ottenere qualcosa che potrebbe essere una primitiva della piattaforma.
La soluzione: l'attributo focusgroup
Con focusgroup, la stessa barra degli strumenti diventa:
<div focusgroup="toolbar" aria-label="Text formatting">
<button type="button">Bold</button>
<button type="button">Italic</button>
<button type="button">Underline</button>
<button type="button">Strikethrough</button>
</div>
Prova dal vivo: Pattern della barra degli strumenti > Barra degli strumenti di base. È tutto. Nessun JavaScript per la navigazione con i tasti freccia. Nessuna gestione manuale di tabindex. Ecco cosa gestisce ora il browser per te:
- Navigazione con i tasti Freccia:spostati tra gli elementi rispettando la modalità e la direzione di scrittura.
- Una singola tabulazione:il browser comprime automaticamente gli elementi partecipanti in una
singola tabulazione. Gli sviluppatori non devono impostare
tabindex="-1"su elementi non attivi. - Memoria dell'ultimo elemento selezionato: quando un utente esce dal gruppo di messa a fuoco e torna, la messa a fuoco viene ripristinata sull'elemento che aveva lasciato.
- Semantica ARIA:il browser fornisce ruoli appropriati (ad esempio
role="toolbar") in base al comportamento scelto quando vengono utilizzati elementi generici.
Gli sviluppatori mantengono solo la logica univoca delle loro funzionalità, come l'attivazione/disattivazione dello stato di pressione, l'apertura dei menu, la gestione della selezione o qualsiasi comando personalizzato.
Panoramica dell'API
L'attributo focusgroup accetta un elenco di token separati da spazi. Il primo
token è sempre un token di comportamento che dichiara il pattern del widget. I token modificatori
facoltativi sono i seguenti: focusgroup="<behavior> [inline|block] [wrap] [nomemory]".
Token comportamentali
Il token di comportamento è obbligatorio (a meno che non utilizzi none per disattivare un focus group
antenato). Dichiara il pattern del widget composito, garantendo che i ruoli
giusti possano essere dedotti quando non sono specificati diversamente. I token seguono i
pattern descritti nella
guida alle pratiche di creazione di Aria
e sono elencati nella tabella seguente:
| Comportamento | Pattern APG | Ruolo minimo del contenitore (se applicato) | Ruolo secondario minimo (se applicato) |
Modificatori predefiniti |
|---|---|---|---|---|
toolbar |
Barra strumenti | barra degli strumenti | (nessuno) | inline |
tablist |
APG Tabs | tablist | scheda | inline wrap |
radiogroup |
Gruppo di opzioni | radiogroup | radio | (nessuno) |
listbox |
Listbox | listbox | option | (nessuno) |
menu |
Menu | menu | menuitem | block wrap |
menubar |
Barra dei menu | menubar | menuitem | inline wrap |
none |
n/a | n/d | n/d | n/a |
Consulta la spiegazione per tutti i dettagli sul funzionamento della mappatura dei ruoli.
Limitazione degli assi (inline e block)
Se il comportamento scelto non ha modificatori predefiniti, tutti e quattro i tasti freccia
servono per spostare lo stato attivo. Puoi limitare la navigazione a un singolo asse logico utilizzando il modificatore inline o block:
inline: il focusgroup risponde solo ai tasti freccia sull'asse in linea, sinistra e destra nella maggior parte dei contesti in lingua inglese (orizzontale, dall'alto verso il basso).block: Il focus group risponde solo ai tasti freccia sull'asse del blocco, su e giù nella maggior parte dei contesti in lingua inglese (orizzontale, dall'alto verso il basso).
La limitazione dell'asse è allineata alle proprietà logiche CSS e si adatta automaticamente alla modalità e alla direzione di scrittura.
Navigazione wrap-around
Per impostazione predefinita, la navigazione con i tasti freccia si arresta ai bordi del focusgroup. Aggiungi il modificatore
wrap per eseguire il loop dall'ultimo elemento al primo (e dal primo
all'ultimo). Se un comportamento è impostato per il wrapping per impostazione predefinita, utilizza il modificatore nowrap
per disattivarlo.
Prova dal vivo: Tablist Pattern > Horizontal Tablist with Wrapping. In questo esempio, quando lo stato attivo è impostato sulla scheda Domande frequenti e l'utente preme il tasto Freccia destra, lo stato attivo torna alla scheda Panoramica.
Attributo focusgroupstart
L'attributo focusgroupstart indica quale elemento riceve lo stato attivo quando si passa a un focusgroup per la prima volta (o ogni volta che la memoria è disattivata):
<div focusgroup="toolbar nomemory" aria-label="Entry point demo">
<button type="button">First</button>
<button type="button" focusgroupstart>Middle (Entry)</button>
<button type="button">Last</button>
</div>
Sia Tab che Maiusc+Tab vengono visualizzati in "Centrale (ingresso)" perché è presente focusgroupstart
e la memoria è disattivata con il modificatore nomemory. Provalo in tempo reale:
Pattern della barra degli strumenti > Punto di accesso con focusgroupstart.
Disattiva la memoria (nomemory)
Per impostazione predefinita, i focus group ricordano l'ultimo elemento attivo e lo ripristinano
quando si rientra con il tasto Tab. Per i pattern in cui la messa a fuoco deve sempre tornare a un punto di ingresso fisso (come nella demo precedente), utilizza il modificatore nomemory nell'attributo focusgroup per disattivarlo.
Questo modificatore può essere combinato anche con lo spostamento programmatico di
focusgroupstart per darti il pieno controllo dell'elemento selezionato quando
entri nel gruppo. La memoria viene cancellata quando l'elemento memorizzato diventa
non disponibile, ad esempio se viene rimosso, nascosto, disattivato, inerte o escluso
dal focus group.
Disattiva (focusgroup="none")
Utilizza focusgroup="none" per escludere un elemento e il relativo sottoalbero dalla navigazione con le frecce di un gruppo di messa a fuoco principale. L'elemento disattivato e il relativo sottoalbero rimangono
raggiungibili utilizzando il tasto Tab, ma i tasti freccia li saltano:
<div focusgroup="toolbar" aria-label="Segmented toolbar">
<button type="button">New</button>
<button type="button">Open</button>
<button type="button">Save</button>
<span focusgroup="none">
<button type="button">Help</button>
<button type="button">Shortcuts</button>
</span>
<button type="button">Close</button>
<button type="button">Exit</button>
</div>
L'utilizzo del tasto Freccia destra consente di passare a Nuovo, quindi Apri, Salva, Chiudi ed Esci, saltando completamente i pulsanti Guida e Scorciatoie. Tuttavia, un utente può comunque accedere alla sezione di assistenza per accedere a questi pulsanti. Prova dal vivo: Additional Concepts > Opt-Out Segments with focusgroup="none".
Pattern comuni
Tablist
Un controllo delle schede con navigazione tramite tasti freccia.
<div focusgroup="tablist nomemory" aria-label="Sections">
<button type="button" aria-selected="true" aria-controls="panel-overview" id="tab-overview" focusgroupstart>Overview</button>
<button type="button" aria-selected="false" aria-controls="panel-features" id="tab-features">Features</button>
<button type="button" aria-selected="false" aria-controls="panel-pricing" id="tab-pricing">Pricing</button>
<button type="button" aria-selected="false" aria-controls="panel-faq" id="tab-faq">FAQ</button>
</div>
<div role="tabpanel" id="panel-overview" aria-labelledby="tab-overview" tabindex="0">...</div>
<div role="tabpanel" id="panel-features" aria-labelledby="tab-features" tabindex="0">...</div>
<div role="tabpanel" id="panel-pricing" aria-labelledby="tab-pricing" tabindex="0">...</div>
<div role="tabpanel" id="panel-faq" aria-labelledby="tab-faq" tabindex="0">...</div>
Prova dal vivo: Tablist Pattern > Horizontal Tablist with Wrapping.
Cosa notare:
- L'attributo
focusgroupstartsi trova nella scheda selezionata, quindi lo stato attivo entra sempre lì. - Il modificatore
nomemorygarantisce che, anche se l'utente si era concentrato in precedenza su un'altra scheda, il rientro avvenga sempre nella scheda selezionata. - Il modificatore
inlinelimita la navigazione tramite frecce ai tasti Freccia sinistra e Freccia destra. Questo corrisponde al comportamento previsto descritto dal pattern Schede APG. - Il modificatore
wrapconsente agli utenti di utilizzare i tasti freccia in modo continuo in tutte le schede. - Il codice dello sviluppatore, omesso per brevità, gestisce la selezione effettiva: aggiornamento di
aria-selected, attivazione/disattivazione della visibilità del riquadro e spostamento dell'attributofocusgroupstartin caso di modifica della selezione.
Menu e barra dei menu
Un semplice menu verticale con navigazione tramite frecce su e giù.
<div focusgroup="menu" aria-label="File actions" class="menu-vertical">
<button type="button" class="menu-item">New</button>
<button type="button" class="menu-item">Open…</button>
<button type="button" class="menu-item">Save</button>
<button type="button" class="menu-item">Exit</button>
</div>
Provalo dal vivo:
Menu and Menubar Pattern > Simple Vertical Menu.
Con il modificatore block, solo i tasti Freccia su e Freccia giù consentono di spostarsi tra gli elementi. I tasti Freccia sinistra e Freccia destra sono liberi per il comportamento che definisci (ad esempio, l'apertura dei sottomenu). Per una barra dei menu con sottomenu nidificati, ogni livello è un focusgroup indipendente. Prova dal vivo:
Menu e barra dei menu > Barra dei menu con sottomenu a comparsa
<ul role="menubar" focusgroup="menubar"
aria-label="Application Menu" class="menubar">
<li role="none">
<button role="menuitem" type="button" class="menubar-item"
aria-haspopup="menu" aria-expanded="false"
popovertarget="filemenu">File</button>
<ul role="menu" focusgroup="menu"
id="filemenu" popover aria-label="File submenu" class="submenu">
<li role="none"><button type="button" class="submenu-item"
autofocus>New</button></li>
<li role="none"><button type="button" class="submenu-item">Open</button></li>
<li role="none"><button type="button" class="submenu-item">Save</button></li>
</ul>
</li>
<!-- More menu items... -->
</ul>
Provalo dal vivo:
Menu e barra dei menu > Barra dei menu con sottomenu a comparsa.
Mentre la barra dei menu utilizza il tasto modificatore inline per la navigazione a sinistra e a destra, i
sottomenu utilizzano il tasto modificatore block per la navigazione verso l'alto e verso il basso. I focus group nidificati
sono completamente indipendenti, quindi non interferiscono tra loro.
Gruppo pulsanti di opzione
Un gruppo di pulsanti di opzione personalizzato con navigazione tramite tasti freccia e controllo completo dello stile.
<div focusgroup="radiogroup" aria-label="Favorite color">
<span aria-checked="false" tabindex="0">Red</span>
<span aria-checked="false" tabindex="0">Green</span>
<span aria-checked="true" tabindex="0" focusgroupstart >Blue</span>
<span aria-checked="false" tabindex="0">Purple</span>
</div>
Prova dal vivo: Pattern gruppo di pulsanti di opzione > Confronto: nativo e Focusgroup.
Mentre l'attributo focusgroup gestisce la navigazione con i tasti freccia, devi
implementare il codice di selezione. In questa demo, il codice JavaScript gestisce lo stato di selezione (utilizzando l'attributo aria-checked).
Concetti fondamentali
Focusgroup item participation
Tutti i discendenti attivabili in sequenza dell'elemento con focusgroup impostato
su un comportamento valido vengono considerati partecipanti al focusgroup. Ciò significa
che gli elementi con un tabindex negativo non vengono presi in considerazione, ma gli elementi attivabili in modo nativo come <button> sì, così come gli elementi in cui hai specificato un tabindex non negativo.
Tabulazione
Non è necessario gestire i valori di tabindex. Anche quando più discendenti
sono naturalmente selezionabili con il tasto Tab (ad esempio, diversi elementi <button>), focusgroup
li comprime in un unico punto di interruzione della tabulazione. Il browser gestisce l'elemento
su cui è possibile spostarsi con il tasto Tab in un determinato momento. Prova in diretta:
Toolbar Pattern > No tabindex Management Needed.
Ultimo ricordo messo a fuoco
Per impostazione predefinita, quando un utente preme Tab per uscire da un focusgroup e poi preme di nuovo Tab per rientrare, lo stato attivo torna all'ultimo elemento selezionato. Questo è fondamentale per elenchi e barre degli strumenti di grandi dimensioni, in modo che gli utenti non perdano il segno. Utilizza il modificatore nomemory per disattivare
questo comportamento quando vuoi che lo stato attivo venga sempre ripristinato sul primo elemento oppure
se utilizzi focusgroupstart, per controllare l'elemento inizialmente selezionato.
Focus group nidificati
Ogni dichiarazione di focusgroup crea un ambito indipendente. Un focus group nidificato disattiva automaticamente la navigazione con le frecce del gruppo principale. Utilizza il tasto Tab per spostarti tra i gruppi di messa a fuoco e i tasti Freccia per navigare all'interno del gruppo di messa a fuoco corrente. Prova dal vivo: Additional Concepts > Nested Focusgroups.
Supporto di Shadow DOM
Per impostazione predefinita, Focusgroup viene applicato ai limiti di shadow DOM. Un focus group dichiarato su un host ombra include elementi su cui è possibile impostare lo stato attivo all'interno dell'albero ombra dell'host. Se vuoi disattivare la funzionalità, puoi utilizzare focusgroup="none" all'interno dell'albero ombra del componente.
Gestione dei conflitti di chiavi
Alcuni elementi all'interno di un focusgroup, come <input>, <textarea> e altri
controlli, utilizzano i tasti freccia per i propri scopi. Quando si verifica un conflitto tra
i tasti di navigazione del focusgroup e il comportamento dei tasti freccia di un elemento nativo:
- I tasti freccia vengono utilizzati dall'elemento interattivo (ad esempio, per lo spostamento del cursore di testo) e focusgroup non interferisce.
- Tab o Maiusc+Tab forniscono un meccanismo di uscita predefinito, che consente a un utente di utilizzare la navigazione tramite Tab per "rientrare" nel focus group.
Questi comportamenti di escape si applicano solo in caso di conflitto effettivo tra tasti;
gli assi non in conflitto non sono interessati. Puoi anche chiamare preventDefault() sugli eventi keydown per ignorare il comportamento dei tasti freccia del focusgroup per elementi specifici. Ciò significa che puoi includere input e aree di testo all'interno di un
focusgroup senza interrompere il comportamento.
Se aggiungi gestori di tasti ai tuoi elementi che partecipano a un focusgroup, fai attenzione a fornire un meccanismo di uscita simile in modo che gli utenti possano accedere al resto del gruppo.
Scoperta dei discendenti profondi
Gli elementi focusgroup non devono essere elementi secondari diretti del contenitore focusgroup.
Il browser considera tutti i discendenti su cui è possibile spostare il focus in sequenza (non negativi
tabindex) per partecipare al gruppo di messa a fuoco, a meno che non si trovino all'interno di un gruppo di messa a fuoco
nidificato o non abbiano partecipato con focusgroup="none".
<div focusgroup="toolbar" aria-label="Nested wrappers">
<div>
<span>
<button type="button">Alpha</button>
</span>
<span>
<button type="button">Beta</button>
</span>
<span>
<button type="button">Gamma</button>
</span>
</div>
</div>
La navigazione con i tasti Freccia funziona anche se i pulsanti sono nidificati all'interno dei wrapper <div> e
<span>. Non è necessario un elenco piatto, quindi gli elementi wrapper per
lo stile vanno bene.
Prova dal vivo: Additional Concepts > Deep Descendants.
Integrazione con la proprietà reading-flow
La navigazione sequenziale (Tab) e direzionale (tasto freccia) rispetta la proprietà CSS
reading-flow quando presente, seguendo l'ordine di lettura visivo anziché
l'ordine del codice sorgente DOM.
In questo modo, la navigazione con i tasti freccia corrisponde al layout visualizzato dagli utenti sullo schermo.
<div focusgroup="toolbar" aria-label="Visual order"
style="display: flex; flex-direction: row-reverse; reading-flow: flex-visual;">
<button type="button">A (DOM first)</button>
<button type="button">B (DOM second)</button>
<button type="button">C (DOM third)</button>
</div>
Mentre l'ordine DOM è A, B, C, l'ordine visivo è C, B, A perché il layout
utilizza flex-direction: row-reverse. Tuttavia, poiché il codice utilizza anche
reading-flow: flex-visual, l'ordine di lettura torna a essere A, B, C e
focusgroup corrisponde a questo ordine.
Se premi Tab, il cursore si sposta prima su C, poi su B e infine su A. Prova dal vivo: Additional Concepts > CSS reading-flow Integration.
Accessibilità
Inferenza del ruolo ARIA
In un focus group, il token comportamentale viene utilizzato dal browser per dedurre un ruolo minimo
sia per il contenitore che per i relativi elementi partecipanti. Ciò significa che quando
l'attributo focusgroup viene impostato su un elemento con un ruolo generico, viene applicato il
ruolo corretto in base al comportamento scelto. I ruoli degli elementi partecipanti che hanno un ruolo generico o dei pulsanti che non hanno un ruolo specificato verranno dedotti di conseguenza. Ad esempio, il seguente codice HTML:
<div focusgroup="tablist">
<button>Tab 1</button>
<button>Tab 2</button>
<button>Tab 3</button>
</div>
Crea il seguente albero di accessibilità, anche se non sono stati definiti ruoli per i pulsanti:
+ tablist
|
+ tab
|
+ tab
|
+ tab
Puoi sempre controllare il comportamento impostando direttamente il ruolo.
Considerazioni sull'accessibilità
Fai attenzione a rispettare il comportamento che hai scelto durante la creazione di un focus group.
L'utilizzo del focus group deve essere il più possibile in linea con il comportamento che hai specificato. Questo è importante per garantire che gli utenti che si affidano a strumenti di accessibilità possano navigare nei contenuti e utilizzare controlli personalizzati.
Sebbene l'inferenza dei ruoli fornisca valori predefiniti validi, quando utilizzi elementi con ruoli non generici, assicurati che abbiano il ruolo corretto impostato per la funzionalità che forniscono.
Quando utilizzi focusgroup, ricorda che gli utenti potrebbero dover scorrere con i tasti freccia per visualizzare i tuoi contenuti. Un utente che utilizza la tastiera deve sempre essere in grado di leggere e accedere ai contenuti della tua pagina.
Rilevamento delle funzionalità
Per iniziare a utilizzare focusgroup oggi, prima che sia completamente supportato su tutti i browser, puoi rilevare il supporto di focusgroup in JavaScript:
if ('focusgroup' in HTMLElement.prototype) {
// focusgroup is supported.
} else {
// fall back to manual roving tabindex.
}
Conclusione
L'attributo focusgroup è in fase di elaborazione da parte degli enti di standardizzazione e stiamo
creando attivamente il prototipo in Chromium e perfezionando l'API.
Provalo e segnala un problema del focus group nello strumento di monitoraggio dei problemi di GitHub di Open-UI. Siamo particolarmente interessati alle tue opinioni su quanto segue:
- La superficie API è adatta ai pattern che crei?
- Ci sono pattern o scenari che ci sfuggono?
- Esistono elementi su cui l'attributo focusgroup non dovrebbe essere consentito?
- Come funziona la storia dell'accessibilità per i tuoi casi d'uso?
Grazie per aver contribuito a migliorare la navigazione da tastiera sul web.
Scopri di più
- Focusgroup Explainer
- Demo interattive (fonte)
- WHATWG HTML Issue
- Open UI Focusgroup Issues
- Guida alle pratiche di creazione ARIA
Grazie a Mason Freed, Sara Higley, Scott O'Hara e al resto della community Open-UI per l'aiuto nel reintrodurre focusgroup.