Publicado em: 5 de março de 2026
O atributo HTML focusgroup é uma maneira declarativa proposta de adicionar navegação por
teclas de seta do teclado a widgets compostos, como barras de ferramentas, listas de guias, menus,
caixas de listagem etc., sem escrever nenhum JavaScript roving-tabindex. Um atributo
substitui centenas de linhas de boilerplate. Queremos seu feedback antes do lançamento.
Faça um teste e envie seu feedback
Você pode testar o focusgroup hoje mesmo no Chrome, Edge e outros navegadores Chromium. Para isso, ative o recurso de uma das duas maneiras a seguir:
- Teste local:no navegador, abra a página
about://flagse ative a flag Recursos experimentais da plataforma da Web. Ou inicie o navegador na linha de comando usando o parâmetro--enable-blink-features=Focusgroup. - Teste de origem:registre-se no teste de origem do grupo focal para testar no seu site com usuários reais.
Em seguida, confira as demonstrações interativas para ver todos os padrões em ação.
Precisamos da sua opinião. Registre um problema do grupo focal para dar sua opinião.
Esse é um esforço entre navegadores:a proposta é da Microsoft pelo OpenUI Community Group com forte apoio do Google. O formato da API pode mudar com base no seu feedback. Vamos conhecer o problema que o grupo focal resolve e como a API funciona.
O problema: tabindex manual
Se você já criou uma barra de ferramentas, uma lista de guias, um menu ou uma caixa de listagem, já escreveu alguma versão desse código. O Guia de práticas de criação da ARIA (APG, na sigla em inglês) recomenda que widgets compostos apresentem uma única parada de tabulação e permitam que os usuários naveguem entre os itens com as teclas de seta. Esse padrão é conhecido como "tabindex itinerante". Muitos frameworks de UI reimplementam isso do 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>
A partir daqui, os desenvolvedores precisam usar JavaScript que detecta teclas de seta para mover o foco e ajustar o atributo tabindex de todos os elementos. Esta é a versão simplificada. Uma implementação de produção também precisa processar:
- Modo de escrita e RTL:ajuste as direções das teclas de seta com base na direção do conteúdo.
- Memória do último foco:restaura o foco para o item ativo anteriormente quando um usuário volta a usar as guias.
- Itens desativados e ocultos:são ignorados durante a navegação.
- Itens dinâmicos:atualize o índice móvel quando itens forem adicionados ou removidos.
A maioria das bibliotecas de UI, incluindo React, Angular CDK e Fluent UI, envia a própria versão dessa lógica. É muito esforço duplicado para conseguir algo que poderia ser uma primitiva de plataforma.
A solução: o atributo focusgroup
Com focusgroup, a mesma barra de ferramentas se torna:
<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>
Teste ao vivo: Padrão de barra de ferramentas > Barra de ferramentas básica. É isso. Não há JavaScript para navegação com teclas de seta. Sem gerenciamento manual de tabindex. Confira o que o navegador faz por você:
- Navegação com teclas de seta:navegue entre os itens respeitando o modo e a direcionalidade de escrita.
- Uma única parada de tabulação:o navegador recolhe automaticamente os itens participantes em uma parada de tabulação. Os desenvolvedores não precisam definir
tabindex="-1"em itens não ativos. - Memória do último foco:quando um usuário sai do grupo de foco e volta, o foco é restaurado para o item em que ele estava.
- Semântica ARIA:o navegador fornece papéis adequados (como
role="toolbar") com base no comportamento escolhido quando elementos genéricos são usados.
Os desenvolvedores mantêm apenas a lógica exclusiva dos recursos, como alternar o estado pressionado, abrir menus, gerenciar a seleção ou qualquer comando personalizado.
Visão geral da API
O atributo focusgroup usa uma lista de tokens separada por espaços. O primeiro token é sempre um token de comportamento que declara o padrão do widget. Os tokens modificadores opcionais são: focusgroup="<behavior> [inline|block] [wrap] [nomemory]".
Tokens de comportamento
O token de comportamento é obrigatório, a menos que você use none para desativar um grupo de foco ancestral. Ele declara o padrão de widget composto, garantindo que as funções corretas possam ser inferidas quando não forem especificadas. Os tokens seguem os padrões descritos no guia de práticas de criação do Aria e estão listados na tabela a seguir:
| Comportamento | Padrão APG | Função mínima do contêiner (quando aplicável) | Função mínima de filho (quando aplicada) |
Modificadores padrão |
|---|---|---|---|---|
toolbar |
Barra de ferramentas Google | barra de ferramentas | (nenhum) | inline |
tablist |
Guias APG | tablist | tab | inline wrap |
radiogroup |
Grupo de opções | radiogroup | radio | (nenhum) |
listbox |
Caixa de listagem | caixa de listagem | option | (nenhum) |
menu |
Menu | menu | menuitem | block wrap |
menubar |
Barra de menus | menubar | menuitem | inline wrap |
none |
N/A | N/A | N/A | N/A |
Consulte a explicação para mais detalhes sobre como o mapeamento de funções funciona.
Restrição de eixo (inline e block)
Se o comportamento escolhido não tiver modificadores padrão, todas as quatro teclas de seta
vão funcionar para mover o foco. É possível restringir a navegação a um único eixo lógico usando o modificador inline ou block:
inline: o focusgroup só responde às teclas de seta no eixo inline, esquerda e direita na maioria dos contextos da língua inglesa (horizontal, de cima para baixo).block: o focusgroup só responde às teclas de seta no eixo do bloco, para cima e para baixo na maioria dos contextos da língua inglesa (horizontal, de cima para baixo).
A restrição de eixo é alinhada com as propriedades lógicas do CSS e se adapta automaticamente ao modo e à direção de escrita.
Navegação wrap-around
Por padrão, a navegação com as teclas de seta para nas bordas do grupo de foco. Adicione o modificador wrap para fazer um loop do último item de volta para o primeiro (e do primeiro de volta para o último). Se um comportamento tiver quebra por padrão, use o modificador nowrap para desativar esse comportamento.
Faça o teste ao vivo: Padrão de lista de guias > Lista de guias horizontal com quebra de texto. Nesse exemplo, quando o foco está na guia Perguntas frequentes e o usuário pressiona a tecla de seta para a direita, o foco volta para a guia Visão geral.
O atributo focusgroupstart
O atributo focusgroupstart marca qual elemento recebe o foco quando você usa a tecla Tab
em um grupo de foco pela primeira vez (ou sempre que a memória está desativada):
<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>
As teclas Tab e Shift+Tab chegam a "Meio (entrada)" porque ele tem focusgroupstart e a memória está desativada com o modificador nomemory. Teste ao vivo:
Padrão de barra de ferramentas > Ponto de entrada com focusgroupstart.
Desativar a memória (nomemory)
Por padrão, os grupos de foco lembram o último item focalizado e o restauram na
reentrada com a tecla Tab. Para padrões em que o foco sempre precisa retornar a um ponto de entrada fixo (como na demonstração anterior), use o modificador nomemory no atributo focusgroup para desativá-lo.
Esse modificador também pode ser combinado com o movimento programático de
focusgroupstart para dar controle total sobre o item que é focado ao
entrar no grupo. A memória é limpa quando o elemento lembrado fica indisponível, por exemplo, se ele for removido, oculto, desativado, inerte ou excluído do focusgroup.
Desativar (focusgroup="none")
Use focusgroup="none" para excluir um elemento e a subárvore dele da navegação por seta de um grupo de foco ancestral. O elemento desativado e a subárvore dele permanecem
acessíveis usando a tecla Tab, mas as teclas de seta os ignoram:
<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>
Usar a tecla de seta para a direita navega até "Novo", "Abrir", "Salvar", "Fechar" e "Sair", pulando completamente os botões "Ajuda" e "Atalhos". No entanto, um usuário ainda pode usar a tecla Tab para acessar a seção de ajuda e encontrar esses botões. Teste agora: Outros conceitos > Segmentos de recusa com focusgroup="none".
Padrões comuns
Tablist
Um controle de guias com navegação por teclas de seta entre elas.
<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>
Faça o teste ao vivo: Padrão de lista de guias > Lista de guias horizontal com quebra de texto.
Atenção aos seguintes pontos:
- O atributo
focusgroupstartestá na guia selecionada, então o foco sempre entra ali. - O modificador
nomemorygarante que, mesmo que o usuário tenha focado em outra guia antes, a reentrada sempre vá para a guia selecionada. - O modificador
inlinerestringe a navegação por setas apenas às teclas esquerda e direita. Isso corresponde ao comportamento esperado descrito no padrão de guias da APG. - O modificador
wrappermite que os usuários usem as teclas de seta continuamente em todas as guias. - O código do desenvolvedor, omitido por brevidade, processa a seleção real: atualizando
aria-selected, alternando a visibilidade do painel e movendo o atributofocusgroupstartna mudança de seleção.
Menu e barra de menus
Um menu vertical simples com navegação por setas para cima e para baixo.
<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>
Teste ao vivo:
Padrão de menu e barra de menus > Menu vertical simples.
Com o modificador block, apenas as teclas de seta para cima e para baixo navegam pelos itens. As setas para a esquerda e para a direita podem ser usadas para o comportamento que você definir (por exemplo, abrir submenus). Para uma barra de menus com submenus aninhados, cada nível é um
grupo de foco independente. Teste ao vivo:
Padrão de menu e barra de menus > Barra de menus com submenus popover
<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>
Teste ao vivo:
Padrão de menu e barra de menus > Barra de menus com submenus popover.
Enquanto a barra de menus usa o modificador inline para navegação à esquerda e à direita, os
submenus usam o modificador block para navegação para cima e para baixo. Os grupos de foco aninhados são completamente independentes e não interferem uns nos outros.
Radiogroup
Um grupo de opções personalizado com navegação por teclas de seta e controle total de estilização.
<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>
Faça o teste ao vivo: Padrão de grupo de opções > Comparação: nativo x grupo focal.
Embora o atributo focusgroup processe a navegação com as teclas de seta, você precisa
implementar o código de seleção. Nesta demonstração, o código JavaScript gerencia o estado
marcado (usando o atributo aria-checked).
Principais conceitos
Participação em itens de grupo de discussão
Todos os descendentes sequencialmente focalizáveis do elemento com focusgroup definido
como um comportamento válido são considerados participantes desse grupo de foco. Isso significa que elementos com um tabindex negativo não são considerados, mas elementos nativamente focáveis, como <button>, são, assim como elementos em que você especificou um tabindex não negativo.
Tabulação
Você não precisa gerenciar valores de tabindex. Mesmo quando vários descendentes
podem ser naturalmente tabulados (por exemplo, vários elementos <button>), o focusgroup
os recolhe em uma única parada de tabulação. O navegador processa qual item pode ser
acessado com a tecla Tab a qualquer momento. Teste ao vivo:
Padrão de barra de ferramentas > Não é necessário gerenciamento de tabindex.
Última recordação em foco
Por padrão, quando um usuário pressiona a tecla Tab para sair de um grupo de foco e depois pressiona Tab novamente, o foco retorna ao último item focado. Isso é fundamental para listas e barras de ferramentas grandes, para que os usuários não percam o lugar. Use o modificador nomemory para desativar esse comportamento quando quiser que o foco seja sempre restaurado para o primeiro elemento ou se estiver usando focusgroupstart para controlar o elemento inicialmente focado.
Grupos de discussão aninhados
Cada declaração de focusgroup cria um escopo independente. Um grupo de foco aninhado desativa automaticamente a navegação por seta do ancestral. Use a tecla Tab para mover entre grupos de foco e as teclas de seta para navegar no grupo atual. Teste ao vivo: Outros conceitos > Grupos de foco aninhados.
Compatibilidade com o shadow DOM
Por padrão, o Focusgroup é aplicado em todos os limites do DOM paralelo. Um grupo de foco declarado em um host de sombra inclui elementos focalizáveis dentro da árvore de sombra desse host. Se quiser desativar, use focusgroup="none" na árvore de sombra do seu
componente.
Tratamento de conflitos de chaves
Alguns elementos dentro de um focusgroup, como <input>, <textarea> e outros controles, usam as teclas de seta para fins próprios. Quando há um conflito entre
as teclas de navegação do focusgroup e o comportamento da tecla de seta de um elemento nativo:
- As teclas de seta são consumidas pelo elemento interativo (por exemplo, para movimento do cursor de texto), e o focusgroup não interfere.
- Tab ou Shift+Tab oferece um mecanismo de escape padrão, permitindo que um usuário use a navegação por Tab para "reentrar" no focusgroup.
Esses comportamentos de escape só se aplicam quando há um conflito de chaves real. Os eixos não conflitantes não são afetados. Você também pode chamar preventDefault() em eventos
keydown para substituir o comportamento das teclas de seta do focusgroup em elementos
específicos. Isso significa que você pode incluir entradas e textareas em um
focusgroup sem interromper nenhum dos comportamentos.
Se você adicionar manipuladores de teclas aos seus próprios elementos que estão participando de um grupo de foco, tome cuidado para fornecer um mecanismo de escape semelhante para que os usuários possam acessar o restante do grupo.
Descoberta de descendentes profundos
Os itens do grupo de foco não precisam ser filhos diretos do contêiner do grupo de foco.
O navegador considera todos os descendentes sequencialmente focalizáveis (tabindex não negativo) para participar do focusgroup, a menos que estejam dentro de um focusgroup aninhado ou tenham recusado com 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>
A navegação com as teclas de seta funciona mesmo que os botões estejam aninhados nos wrappers <div> e <span>. Não há um requisito de lista simples, então os elementos de contêiner para
estilização são adequados.
Teste ao vivo: Outros conceitos > Descendentes profundos.
Integração com a propriedade reading-flow
A navegação sequencial (Tab) e direcional (tecla de seta) respeitam a propriedade CSS
reading-flow quando presente, seguindo a ordem de leitura visual em vez
da ordem de origem do DOM.
Isso garante que a navegação com as teclas de seta corresponda ao layout que os usuários veem na tela.
<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>
Enquanto a ordem do DOM é A, B, C, a ordem visual é C, B, A porque o layout usa flex-direction: row-reverse. No entanto, como o código também usa
reading-flow: flex-visual, a ordem de leitura volta a ser A, B, C e
focusgroup corresponde a essa ordem.
Ao pressionar a tecla Tab, o foco vai para C. Ao pressionar a seta para a direita, o foco vai para B e depois para A. Teste ao vivo: Additional Concepts > CSS reading-flow Integration.
Acessibilidade
Inferência de papéis ARIA
Em um grupo focal, o token de comportamento é usado pelo navegador para inferir uma função mínima para o contêiner e os itens participantes. Isso significa que, quando o atributo
focusgroup é definido em um elemento com uma função genérica, a
função correta, com base no comportamento escolhido, é aplicada. Os itens participantes do elemento que têm uma função genérica ou botões que não têm uma função especificada terão as funções inferidas de acordo. Por exemplo, o
seguinte HTML:
<div focusgroup="tablist">
<button>Tab 1</button>
<button>Tab 2</button>
<button>Tab 3</button>
</div>
Cria a seguinte árvore de acessibilidade, mesmo que nenhuma função tenha sido definida nos botões:
+ tablist
|
+ tab
|
+ tab
|
+ tab
Você pode controlar o comportamento definindo a função diretamente.
Considerações sobre acessibilidade
Respeite o comportamento escolhido ao criar um grupo de foco.
O uso do Focusgroup precisa estar o mais alinhado possível ao comportamento especificado. Isso é importante para garantir que os usuários que dependem de ferramentas de acessibilidade possam navegar pelo conteúdo e usar controles personalizados.
Embora a inferência de função forneça bons padrões, ao usar elementos com funções não genéricas, tome cuidado para garantir que eles tenham a função adequada definida para a funcionalidade que oferecem.
Ao usar focusgroup, lembre-se de que os usuários precisam rolar com as teclas de seta para ver seu conteúdo. Sempre deve haver uma maneira de um usuário de teclado ler e acessar o conteúdo da página.
Detecção de recursos
Para começar a usar o focusgroup hoje, antes que ele seja totalmente compatível com todos os navegadores, detecte a compatibilidade com focusgroup em JavaScript:
if ('focusgroup' in HTMLElement.prototype) {
// focusgroup is supported.
} else {
// fall back to manual roving tabindex.
}
Conclusão
O atributo focusgroup está progredindo nos órgãos de padrões, e estamos
construindo ativamente o protótipo no Chromium e refinando a API.
Teste e registre um problema de grupo focal no rastreador de problemas do Open-UI no GitHub. Estamos especialmente interessados nas suas opiniões sobre o seguinte:
- A plataforma da API parece adequada para os padrões que você cria?
- Há padrões ou cenários que estamos perdendo?
- Há elementos em que o atributo focusgroup não deve ser permitido?
- Como a história de acessibilidade funciona para seus casos de uso?
Agradecemos por ajudar a melhorar a navegação por teclado na Web.
Saiba mais
- Explicação sobre grupos de discussão
- Demonstrações interativas (fonte)
- Problema do HTML da WHATWG
- Problemas abertos do grupo de discussão da interface
- Guia de práticas de criação do ARIA (em inglês)
Agradecemos a Mason Freed, Sara Higley, Scott O'Hara e o restante da comunidade Open-UI pela ajuda para trazer o focusgroup de volta.