Shortcut
O focus não funciona em:
Tags não focalizáveis por padrão (exemplo:
div
)Tags com o atributo
tabindex
com valores negativosTags
<input type="hidden" />
Tags
input
oubutton
com o atributodisabled
Tags
<a>
sem o atributohref
Elementos ocultos ou dentro de um elemento oculto
Dentro de um evento de mousedown sem um preventDefault()
Em alguns momentos o focus não funciona, não adianta.
Mas felizmente é fácil de descobrir o motivo.
Resolvi escrever esse artigo inspirado no post 4 razões pelas quais seu z-index não está funcionando (e como corrigi-lo) .
Expliquei sobre o mínimo sobre focus com HTML, CSS e Javascript nesse post . Se você ainda conhece pouco sobre esse efeito, seria bem legal dar uma lida.
Para escrever esse artigo, testei o focus sempre de duas formas:
Com a tecla
tab
até chegar no elementoE com o método
element.focus();
do Javascript
Veja agora os motivos que fazem o focus não funcionar
O focus não funciona no elemento porque o tabindex não deixa
Se um elemento tiver o atributo tabindex
com um valor negativo, dê adeus ao focus.
Esse é um recurso bem comum para desabilitar o foco no elemento. Porém funciona apenas para o focus via tecla tab
, pois se você usar o element.focus()
, ainda será possível focar.
É importante ficar claro que nem todos elementos são focalizáveis.
Uma div
por exemplo, não pode receber focus em seu estado padrão:
<div>
<!-- ... -->
</div>
div {
background-color: white;
}
div:focus {
background-color: coral;
}
O trecho background-color: coral
só será visualizado, se você tornar essa div
focalizável. Para isso, adicione o atributo tabindex
com o valor 0
ou superior:
<div tabindex="0">
<!-- Meu código -->
</div>
Por outro lado, o tabindex
também serve para desabilitar o focus em algum elemento focalizável por padrão. Você pode fazer isso em qualquer um deles, basta adicionar um valor negativo a esse atributo:
<button tabindex="-1">
Botão não focalizável
</button>
Falei mais sobre o tabindex nesse outro post .
A tag <input> possui um type="hidden"
Essa é fácil.
O focus não funciona pois ele é um recurso visual, e essa tag é oculta por padrão:
<input type="hidden" />
Essa tag é uma exceção, pois todos os outros campos de formulário são focalizáveis.
Além do atributo type="hidden"
na input, existem outros atributos que podem fazer o focus não funcionar.
O atributo disabled está presente
O atributo disabled
desativa um elemento.
Ele pode desabilitar todas as funcionalidades dos elementos de formulários, como inputs
e buttons
.
<input type="text" disabled />
<button type="submit" disabled>Enviar dados</button>
Assim, além de desativar o clique e o preenchimento, eles também não podem receber focus.
O atributo href está ausente
A tag <a>
é outra onde o focus não funciona por causa de atributos. Mas nesse caso, o navegador exige que você informe o destino do link através do atributo href
:
<a href="my_page">É focalizável</a>
<a href="#">É focalizável</a>
<a href="">É focalizável</a>
<a href>É focalizável</a>
<a>Não é focalizável</a>
Nesse post eu ensino um pouco mais sobre como trabalhar com botões e links em HTML .
O elemento focalizável está oculto ou dentro de um elemento oculto
Já perdi os cabelos uma vez no trabalho por causa desse motivo.
Imagine a situação: existe um botão que precisa receber focus assim que o modal (seu elemento pai) é aberto. Mas o focus não funcionava de jeito nenhum, e o código já estava cheio de console.log
.
Assim que descobri o motivo, resolvi fazer esse post.
O código Javascript estava mais ou menos assim:
button.focus();
openModal();
Ou seja, eu ativei o focus em um botão dentro de um modal oculto. Isso não funciona, a menos que eu inverta essas duas linhas:
openModal();
button.focus();
Agora sim o focus funcionou, pois é aplicado em um elemento já visível na tela.
Esse problema acontece ao aplicar focus em um elemento:
Com
display: none
Com
visibility: hidden
Dentro de outro elemento com
display: none
Dentro de outro elemento com
visibility: hidden
Por fim, existe outra situação onde o focus não funciona, que é quando você usa Javascript.
O focus está dentro de um evento de mousedown sem um preventDefault()
Respira fundo que a explicação é longa.
Segundo o artigo da MDN sobre focus() , se você chamar esse método dentro de um evento de mousedown
sem prevenir o comportamento default, o focus não funciona.
Veja agora parte por parte:
<button id="click">CLICK</button>
<button id="focus">FOCUS</button>
Aqui tem dois botões, e o evento de mousedown
no primeiro ativa o focus no segundo:
document.getElementById('click').onmousedown = event => {
document.getElementById('focus').focus();
}
Mas assim o foco permanecerá no button com id click
, pois esse é o comportamento padrão do navegador: focar em um botão que foi clicado.
Para resolver isso, você deve prevenir o comportamento padrão, e logo depois disso ativar o focus no botão desejado:
document.getElementById('click').onmousedown = event => {
event.preventDefault() // aqui a solução
document.getElementById('focus').focus();
}
Vale lembrar que se o evento for de onclick
, você não precisa adicionar essa linha:
document.getElementById('click').onclick = event => {
// nada
document.getElementById('focus').focus();
}
Mas o problema não é apenas quando o focus não funciona. Muitas vezes, funcionar também pode ser um problema
Motivos pelos quais o focus funciona (mas não deveria)
Me deixe-me eu me explicar-me.
Conforme eu testava tudo o que mostrei aqui, descobri que existem situações onde o focus funciona, mas não deveria. Os motivos:
Comportamento inesperado pelos usuários
Experiência ruim
Acessibilidade atrapalhada
A primeira situação é um elemento sem opacidade:
<button class="visible">Botão visível</button>
<button class="invisible">Botão invisível</button>
.visible {
opacity: 1;
}
.invisible {
opacity: 0;
}
O segundo botão, apesar de não ser visível na tela, é focalizável. Isso pode confundir o usuário.
Porém (atenção) se o botão com opacidade zero realmente precisa de focus, não deixe de trocar a opacidade dele para 1 usando a pseudoclasse:
.visible {
opacity: 1;
}
.invisible {
opacity: 0;
}
.invisible:focus {
opacity: 1; /* Mostrando o botão invisível no focus */
}
Um exemplo dessa aplicação são os botões de Skip to content. Para ver um deles em ação, pesquise qualquer coisa no Google, e tecle tab
.
Se o seu elemento focalizável estiver dentro de outro elemento com opacidade zero, acontece a mesma coisa.
Outra situação onde o focus funciona, mas não deveria, é em elementos pequenos demais.
Se você criar um botão assim:
button {
display: block;
width: 1px;
height: 1px;
padding: 0;
margin: 0;
}
Ainda será possível focar nele, apesar de ser quase impossível clicá-lo.
Aqui vale o mesmo aviso de antes: se o elemento pequeno demais realmente precisa de focus, não deixe de torná-lo maior quando isso acontecer. Algo como:
button:focus {
display: block;
min-width: 40px;
min-height: 16px;
padding: 1rem;
}
Por fim, existe uma diferença de comportamento quando o focus não funciona das duas maneiras testadas (com a tecla tab
e com Javascript). Veja abaixo.
O que acontece quando o focus não funciona
Imagine um HTML simples com 3 links:
<a class="link-1" href="#"> <!-- o focus está aqui -->
Link 1
</a>
<a class="link-2"> <!-- focus desabilitado -->
Link 2
</a>
<a class="link-3" href="#">
Link 3
</a>
Suponha que o focus esteja no Link 1, e que esteja desabilitado no Link 2. Quando você pressionar tab
, o focus saltará do Link 1 para o Link 3.
Por outro lado, caso tente focar o Link 2 via Javascript, o focus permanecerá no button 1.
Callback
Em alguns elementos, o focus não funciona. Entre eles:
Tag
input
do tipohidden
Tag
input
com atributodisabled
Tag
button
com atributodisabled
Tag
a
sem atributohref
O elemento está oculto ou dentro de um elemento oculto
O focus é aplicado dentro de um evento de
mousedown
sem umpreventDefault()
Por outro lado, o focus pode funcionar e confundir o usuário. Então revise os elementos que recebem focus porém estão invisíveis pela propriedade opacity
ou pequenos demais para serem clicados e visualizados.
Quando o focus não funciona em algum elemento, a tecla tab
"pula" e foca no próximo. Já em Javascript, o elemento focado continua sendo o último.
Você sempre pode descobrir qual é o elemento em foco através da propriedade document.activeElement
.
Obrigado pela sua leitura.
E focus nos estudos!