Foco

Elementos interativos, incluindo controles de formulário, links e botões, são focalizáveis e tabulares por padrão. Os elementos com tabulação fazem parte da ordem de navegação de foco sequencial do documento. Outros elementos são inertes, o que significa que não são interativos. Com os atributos HTML, é possível tornar os elementos interativos inerentes e tornar os elementos inertes interativos.

Por padrão, a ordem do foco da navegação é a mesma que a visual, que é a ordem do código-fonte. Há atributos HTML que podem alterar essa ordem, e propriedades CSS que podem alterar a ordem visual do conteúdo. Mudar a ordem de tabulação com HTML ou a ordem de renderização visual com CSS pode prejudicar a experiência do usuário.

Não altere a ordem de tabulação percebida e real com CSS e HTML. Como mostrado nos dois exemplos a seguir, as ordens de tabulação diferentes da ordem visualmente esperada são confusas para os usuários e ruins para a experiência deles.

Neste exemplo, o valor do atributo tabindex tornou a ordem da tabulação caótica:

Neste exemplo, o CSS criou uma divergência entre a ordem da tabulação e a ordem visual do conteúdo:

A declaração flex-flow: row-reverse; inverteu a ordem visual. Além disso, a propriedade CSS order era aplicada à sexta palavra, "This", que moveu visualmente essa palavra. A sequência de tabulação é a ordem do código, que não corresponde mais à ordem visual, criando uma desconexão para usuários de teclado.

Como tornar elementos inertes interativos

Os atributos contenteditable e tabindex, sendo atributos globais, podem ser adicionados a qualquer elemento, tornando-os focalizáveis no processo. Os elementos focalizáveis também podem ser focados com um mouse ou ponteiro, definindo o atributo autofocus ou por um script, como element.focus().

O atributo tabindex

O atributo tabindex global, introduzido em atributos, ativa elementos que, de outra forma, não poderiam receber foco, geralmente com a tecla Tab. Por isso esse nome vem por aí.

O atributo tabindex assume como valor um número inteiro. Um valor negativo torna um elemento focalizável, mas não tabulável. Um valor tabindex de 0 torna o elemento focalizável e com tabulação, adicionando o elemento em que ele é aplicado à ordem de navegação de foco sequencial na ordem do código-fonte. Um valor de 1 ou maior torna o elemento focalizável e compatível com tabulação, mas o adiciona a uma sequência de tabulação priorizada e, como vimos acima, precisa ser evitado.

Nesta página, o botão de compartilhamento, <share-action>, é um elemento personalizado. O tabindex="0" adiciona esse elemento que normalmente não é focalizável à ordem de tabulação padrão do teclado:

<share-action authors="@front-end.social/@estellevw" data-action="click" data-category="web.dev" data-icon="share" data-label="share, mastodon" role="button" tabindex="0">
  <svg aria-label="share" role="img" xmlns="http://www.w3.org/2000/svg">
    <use href="#shareIcon" />
  </svg>
  <span>Share</span>
</share-action>

Há outro elemento personalizado nessa página: a navegação local tem um elemento personalizado com um valor tabindex negativo:

<web-navigation-drawer type="standard" tabindex="-1">

Um atributo tabindex com um valor negativo torna o elemento focalizável, mas não com tabulação. O elemento é capaz de receber foco, por exemplo, via HTMLElement.focus(), mas não faz parte da ordem de navegação de foco sequencial. A convenção para elementos focalizáveis e não tabulares é usar tabindex="-1". Se você adicionar um tabindex="-1" a um elemento interativo, ele não poderá mais ser usado com a tecla Tab.

O método element.focus() pode ser usado para definir o foco em elementos focalizáveis. Os navegadores rolam os elementos focados para serem vistos. Por isso, evite usar element.focus({preventScroll:true}), já que focar em um elemento não visível resulta em uma experiência ruim para o usuário.

Se você quiser consultar o documento para descobrir qual elemento está em foco, use a propriedade somente leitura Document.activeElement.

Elementos com um tabindex de 1 ou maior são incluídos em uma sequência de tabulação separada. Como você notará no Codepen, a tabulação começa em uma sequência separada, do menor para o maior valor, antes de passar pelos itens na sequência normal (sem tabindex definido ou tabindex="0") na ordem de origem:

tabindex com um valor positivo coloca o elemento em uma sequência de foco priorizada, o que pode levar ao caos da ordem de foco. Evite modificar a ordem do DOM com tabindex. Além de criarem más experiências do usuário, os pedidos de tabulação alterados também são difíceis de gerenciar e manter.

O atributo contenteditable

O atributo contenteditable já foi discutido. Definir contenteditable="true" em qualquer elemento o torna editável, focável e parte da ordem da tabulação. O comportamento do foco é semelhante à configuração de tabindex="0", mas não é o mesmo. Os elementos contenteditable aninhados são focalizáveis, mas não tabuláveis. Para permitir a tabulação de um elemento contenteditable aninhado, adicione tabindex="0", que vai adicioná-lo à ordem de navegação de foco sequencial.

Focar elementos interativos

O atributo autofocus

Embora o booleano autofocus seja um atributo global que pode ser definido em qualquer elemento, ele não torna um elemento inerte interativo. Quando a página é carregada, o primeiro elemento focalizável com o atributo autofocus definido recebe foco, desde que esse elemento seja exibido e não aninhado em um <dialog>.

Definir automaticamente o foco no conteúdo pode ser confuso. Definir autofocus em um controle de formulário significa que ele será exibido na tela quando a página for carregada. Todos os seus usuários, incluindo usuários de leitores de tela e usuários com janelas de visualização pequenas, podem não "ver" as instruções do formulário, possivelmente rolando a página além do marcador normalmente visível do controle. O atributo autofocus não muda a ordem de navegação de foco sequencial do documento. Os elementos na sequência que vêm antes do elemento com foco automático são simplesmente ignorados. Por esses motivos, não é aconselhável incluir o atributo autofocus.

A exceção à recomendação "não usar autofocus" é incluir o atributo autofocus nos elementos <dialog>. Quando uma caixa de diálogo é aberta, o navegador foca automaticamente no primeiro elemento interativo focalizável dentro da <dialog>, o que significa que autofocus não é necessário para um elemento. Para garantir que um elemento interativo específico da caixa de diálogo receba foco quando ela for aberta, adicione o atributo autofocus a esse elemento.

<dialog open>
  <form method="dialog">
    <button type="submit" autofocus>close</button>
  </form>
</dialog>

O atributo autofocus definido no <button> de fechamento garante que ele receba foco quando a caixa de diálogo é aberta. Como o primeiro elemento na caixa de diálogo, ele teria recebido foco em qualquer caso. Por padrão, quando uma caixa de diálogo é aberta, o primeiro elemento focalizável da caixa de diálogo recebe o foco, a menos que outro elemento tenha o atributo autofocus definido.

Como inerte elementos interativos

Há também atributos HTML que podem remover elementos interativos da sequência de tabulação. Incluir um tabindex negativo a elementos focalizáveis, adicionar o atributo disabled aos controles de formulário compatíveis e adicionar o atributo inert global a um contêiner torna os elementos não tabuláveis. Esses três atributos NÃO são intercambiáveis.

Valor tabindex negativo

Como aprendemos acima, um atributo tabindex com um valor negativo torna um elemento focalizável, mas não com tabulação. Embora não seja necessário adicionar tabindex="0" a um elemento focalizável por padrão, incluindo links, botões, controles de formulários e elementos que são contenteditable, não é necessário incluir um tabindex com um valor negativo, que remove os elementos normalmente tabuláveis da ordem de navegação do foco sequencial.

Um valor negativo de tabindex impede que os usuários do teclado se concentrem em elementos interativos, mas não desativa o elemento. Os usuários do ponteiro ainda podem focar no elemento. Para desativar um elemento, use o atributo disabled.

Desativado

O atributo booleano desativado torna os controles do formulário em que ele é aplicado e os descendentes, se houver, fora de foco. Os controles de formulário desativados não podem ser focados, não recebem eventos de clique e não são enviados após o envio do formulário. Observe que disabled não é um atributo global. Ela se aplica a <button>, <input>, <optgroup>, <option>, <select>, <textarea>, elementos personalizados associados a formulários e <fieldset>. Quando definido em <optgroup> ou <fieldset>, todos os controles de formulários filhos são desativados, exceto o conteúdo do primeiro <legend> da <fieldset>.

Os mesmos elementos com suporte a disabled também podem ser segmentados com as pseudoclasses :disabled e :enabled. Os elementos desativados com o atributo disabled geralmente são estilizados em cinza claro pela folha de estilo do user agent, mesmo que um accent-color esteja definido.

Por ser um atributo booleano, a presença do atributo desativa o elemento ativado. Ele não pode ser definido como false. Para reativar um elemento desativado, o atributo precisa ser removido, geralmente usando Element.removeAttribute('disabled').

A propriedade HTMLInputElement.disabled permite verificar se uma entrada está desativada. Como disabled não é um atributo global, ele não é herdado do HTMLElement, mas cada interface de elemento de suporte, como HTMLSelectElement e HTMLTextareaElement, tem a mesma propriedade somente leitura.

O atributo disabled não se aplica a elementos normalmente inert que são focalizáveis usando tabindex ou contenteditable. Ele também não se aplica ao próprio elemento <form>. Para desativá-los, use o atributo global inert.

O atributo inert

Quando o atributo booleano global inert é adicionado a um elemento, esse elemento e todo o conteúdo aninhado são desativados, não clicáveis nem com tabulação, e removidos da árvore de acessibilidade. Embora inert possa ser aplicado a qualquer elemento, ele geralmente é usado para seções de conteúdo, como conteúdo fora da tela ou oculto.

Ao aplicar disabled aos controles de formulários, o navegador oferece o estilo padrão e pode ser estilizado usando a pseudoclasse :disabled. O atributo inert não fornece indicadores visuais e não tem pseudoclasse correspondente, embora o seletor de atributo [inert] seja correspondente.

O uso de inert em conteúdo visível sem estilos indicando a inércia pode levar a uma experiência do usuário ruim. Como o conteúdo inerte não está disponível para usuários de leitores de tela, pode causar confusão quando eles veem um conteúdo na tela indisponível para as ferramentas de acessibilidade. Torne a inércia muito aparente por meio de CSS.

O foco nunca pode se mover para conteúdo não visível. Qualquer item renderizado fora da tela que não apareça automaticamente quando o foco estiver em foco precisa ser inerte. Se o conteúdo estiver oculto, mas aparecer na visualização em foco, como o link skip to content nesta página, ele não precisa ser inerte.

Teste seu conhecimento

Teste seu conhecimento

Teste seus conhecimentos sobre foco.

Se um elemento não puder ser focado, ele é descrito como?

Empty.
Tente de novo.
Inerte.
Correto.
Oculto.
Tente de novo.

O que acontecerá se o elemento tiver um atributo disabled?

Isso ficará fora de foco.
Correto.
Ele não será exibido.
Tente de novo.
Se for um elemento de formulário, ele não será enviado.
Correto.