Richiesta di feedback degli sviluppatori: focus group

Jacques Newman
Jacques Newman

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:

  1. Test locale:nel browser, apri la pagina about://flags e 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.
  2. 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>
La barra dei menu con il pulsante del corsivo selezionato.

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>
Una barra dei menu con il pulsante centrale selezionato.

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>
Un menu con i pulsanti Guida e Scorciatoia disattivati.

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>
La scheda Panoramica è attiva.

Prova dal vivo: Tablist Pattern > Horizontal Tablist with Wrapping.

Cosa notare:

  • L'attributo focusgroupstart si trova nella scheda selezionata, quindi lo stato attivo entra sempre lì.
  • Il modificatore nomemory garantisce che, anche se l'utente si era concentrato in precedenza su un'altra scheda, il rientro avvenga sempre nella scheda selezionata.
  • Il modificatore inline limita la navigazione tramite frecce ai tasti Freccia sinistra e Freccia destra. Questo corrisponde al comportamento previsto descritto dal pattern Schede APG.
  • Il modificatore wrap consente 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'attributo focusgroupstart in caso di modifica della selezione.

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>
Un menu verticale con la voce di menu Apri selezionata.

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>
Un menu a discesa con l&#39;elemento di copia attivo.

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>
Un gruppo di pulsanti di opzione con il colore blu selezionato.

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>
L&#39;elemento A è attivo.

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ù

Grazie a Mason Freed, Sara Higley, Scott O'Hara e al resto della community Open-UI per l'aiuto nel reintrodurre focusgroup.