Eventos focus e blur em JavaScript
Aprenda como os eventos focus e blur do JavaScript funcionam, como diferem de focusin e focusout, e como usá-los para validação de formulários e acessibilidade.
O JavaScript oferece controle preciso sobre qual elemento está atualmente focado — o elemento que recebe a entrada do teclado. Os eventos focus e blur permitem reagir no momento em que um elemento ganha ou perde o foco, o que é a base para validação inline de formulários, destaque do campo ativo, criação de widgets acessíveis pelo teclado e orientação dos usuários por um formulário. Este artigo aborda o que são esses eventos, como diferem de seus equivalentes com borbulhamento focusin/focusout, e vários padrões práticos.
Esta página baseia-se na introdução a eventos do navegador. Se você precisar lidar com eventos em muitos elementos ao mesmo tempo, leia também sobre borbulhamento e captura.
Entendendo Focus e Blur em JavaScript
O evento focus é disparado quando um elemento se torna o alvo ativo da entrada do teclado — o elemento para o qual document.activeElement aponta. O evento blur é disparado quando esse elemento perde o foco, por exemplo porque o usuário clicou em outro lugar, pressionou Tab ou o foco foi movido programaticamente.
Por padrão, apenas elementos interativos podem receber foco: links (<a href>), controles de formulário (<input>, <textarea>, <select>, <button>) e alguns outros. Para tornar qualquer elemento focável — um <div>, <span> ou <li> — dê a ele um atributo tabindex. Use tabindex="0" para colocá-lo na ordem natural de tabulação, ou tabindex="-1" para torná-lo focável apenas via script (element.focus()).
Um ponto crítico a observar: focus e blur não borbulham. Um listener anexado a um elemento pai não será disparado quando um input descendente ganhar foco. Quando você precisar de delegação de eventos em um contêiner, use os equivalentes com borbulhamento focusin e focusout — eles se comportam de forma idêntica, mas propagam pela árvore DOM.
Focus vs. Blur vs. Focusin vs. Focusout
| Evento | Disparado quando | Borbulha? |
|---|---|---|
focus | elemento ganha foco | Não |
blur | elemento perde foco | Não |
focusin | elemento ganha foco | Sim |
focusout | elemento perde foco | Sim |
Para um único elemento conhecido, focus/blur são os mais simples. Para um formulário inteiro ou uma lista de campos, anexe focusin/focusout uma vez no contêiner.
Como Implementar Eventos Focus
Para usar o evento focus, anexe um listener ao elemento. O exemplo abaixo destaca um input no momento em que ele ganha foco:
<input type="text" id="nameInput" placeholder="Enter Your Name">
<script>
document.getElementById('nameInput').addEventListener('focus', function(event) {
event.target.style.backgroundColor = 'lightblue';
});
</script>Este trecho de código torna o fundo do campo de input azul claro quando ele recebe foco, melhorando a interface do usuário ao indicar onde o usuário está digitando no momento. Para estilização simples, considere usar a pseudo-classe CSS `:focus` como uma alternativa padrão sem JavaScript:
input:focus {
background-color: lightblue;
}Como Implementar Eventos Blur
Validar no blur é um dos usos mais comuns desses eventos: você deixa o usuário terminar de digitar e verifica o valor quando ele sai do campo. Veja como validar um endereço de e-mail quando o input perde o foco:
<input type="email" id="emailInput" placeholder="Enter Your Email">
<script>
document.getElementById('emailInput').addEventListener('blur', function(event) {
// Simplified regex for educational purposes
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(event.target.value)) {
alert('Please enter a valid email address.');
event.target.style.backgroundColor = 'salmon';
} else {
event.target.style.backgroundColor = 'lightgreen';
}
});
</script>Este script verifica se o e-mail digitado corresponde a um formato de e-mail padrão e alerta o usuário se a entrada for inválida. A cor de fundo muda para verde se válida e para salmão se não, fornecendo feedback visual imediato.
Focando Elementos com Script
Além de reagir a eventos, você pode mover o foco você mesmo com element.focus() e removê-lo com element.blur(). Isso é útil para enviar o cursor ao primeiro campo no carregamento da página, ou retornar o foco a um campo inválido após a validação.
<input id="search" placeholder="Search..." />
<button id="go">Focus the search box</button>
<script>
document.getElementById('go').addEventListener('click', () => {
document.getElementById('search').focus();
});
</script>Dois extras úteis:
document.activeElementsempre retorna o elemento que atualmente tem foco (ou<body>se nenhum tiver). É útil para verificar o estado do foco sem listeners.focus({ preventScroll: true })foca um elemento sem rolar para exibi-lo — útil quando você gerencia a rolagem você mesmo.
Para um campo que deve ser focado assim que a página carregar, o atributo HTML autofocus (<input autofocus>) é a opção declarativa sem JavaScript.
Usando focusin/focusout para Delegação
Como focus e blur não borbulham, anexar um listener a um formulário não capturará mudanças de foco nos seus inputs. Os eventos com borbulhamento focusin/focusout resolvem isso — você gerencia cada campo a partir de um único listener no elemento pai:
<form id="signup">
<input name="email" placeholder="Email" />
<input name="password" type="password" placeholder="Password" />
</form>
<script>
const form = document.getElementById('signup');
form.addEventListener('focusin', (event) => {
event.target.style.outline = '2px solid royalblue';
});
form.addEventListener('focusout', (event) => {
event.target.style.outline = '';
});
</script>O evento focusout também expõe event.relatedTarget — o elemento que receberá o foco a seguir — o que permite saber para onde o foco está indo.
Técnicas Avançadas: Gerenciando Múltiplos Campos
Quando um usuário preenche corretamente um campo do formulário, você pode mover automaticamente o foco para o próximo input ao sair do campo atual. Isso simplifica o preenchimento do formulário, eliminando a necessidade de cliques manuais. Veja como implementar esse comportamento:
<input type="text" id="firstName" placeholder="First Name" />
<input type="text" id="lastName" placeholder="Last Name" />
<div id="error" style="color: red;"></div> <!-- Display error message here -->
<script>
document.getElementById('firstName').addEventListener('blur', validateFirstName);
function validateFirstName(event) {
const input = event.target;
const errorDiv = document.getElementById('error');
// Allow only letters and spaces, must not be empty
const nameRegex = /^[A-Za-z ]+$/;
if (!nameRegex.test(input.value)) {
errorDiv.textContent = 'Please enter a valid first name.'; // Display error message
input.style.backgroundColor = 'salmon'; // Set background to salmon on invalid input
input.focus(); // Keep focus on the first name input to encourage correction
} else {
input.style.backgroundColor = 'white'; // Reset background to white on valid input
errorDiv.textContent = ''; // Clear error message
document.getElementById('lastName').focus(); // Optionally move focus to the last name input
}
}
</script>Este exemplo move automaticamente o foco para o campo lastName assim que um primeiro nome válido é inserido, melhorando a experiência do usuário ao reduzir a necessidade de cliques manuais.
Chamar
input.focus()dentro de um handlerblurpode conflitar com o usuário. Se eles estavam tentando clicar em um elemento diferente, refocalizar o campo pode parecer uma armadilha. Use esse padrão com moderação e prefira exibir uma mensagem de erro que o usuário possa corrigir no seu próprio ritmo.
Armadilhas Comuns
- Não espere que
focus/blurborbulhem. Um listener em um contêiner parafocusnunca será disparado; mude parafocusin/focusoutpara delegação. bluré executado antes que o clique em outro controle seja concluído. Se um handlerblurocultar ou remover um elemento que o usuário acabou de clicar, o clique pode não ser registrado — verifiqueevent.relatedTargetprimeiro.- Elementos ocultos ou com
display:nonenão podem receber foco.element.focus()silenciosamente não faz nada neles. - Forçar o foco prejudica a acessibilidade quando é inesperado. Mantenha a ordem de tabulação do teclado previsível e evite prender o foco.
- Para estilização visual pura do foco, prefira as pseudo-classes CSS
:focus/:focus-visibleem vez de JavaScript — elas não requerem listeners e funcionam corretamente com interação apenas pelo teclado.
Conclusão
Os eventos de foco e blur são a espinha dorsal de formulários interativos e acessíveis. Saber que focus/blur não borbulham (e que focusin/focusout borbulham), como mover o foco com element.focus(), e onde traçar a linha entre JavaScript e a pseudo-classe CSS :focus permite criar experiências de entrada responsivas sem surpreender seus usuários.
A seguir, explore interações relacionadas do navegador: eventos de teclado, os eventos change, input, cut, copy, paste e borbulhamento e captura para delegação.