Eventi focus e blur in JavaScript
Scopri come funzionano gli eventi focus e blur in JavaScript, le differenze da focusin e focusout, e come usarli per la validazione dei form e gli input accessibili.
JavaScript offre un controllo preciso sull'elemento attualmente in focus — l'elemento che riceve l'input da tastiera. Gli eventi focus e blur permettono di reagire nel momento in cui un elemento acquisisce o perde il focus, il che costituisce la base per la validazione inline dei form, l'evidenziazione del campo attivo, la creazione di widget accessibili da tastiera e la guida degli utenti attraverso un form. Questo articolo spiega cosa sono questi eventi, come si differenziano dai loro equivalenti con bubbling focusin/focusout, e alcuni pattern pratici.
Questa pagina si basa sull'introduzione agli eventi del browser. Se hai bisogno di gestire eventi su molti elementi contemporaneamente, leggi anche la sezione su bubbling e capturing.
Comprendere focus e blur in JavaScript
L'evento focus si attiva quando un elemento diventa il target attivo dell'input da tastiera — l'elemento a cui punta document.activeElement. L'evento blur si attiva quando quell'elemento perde il focus, ad esempio perché l'utente ha cliccato altrove, premuto Tab, oppure il focus è stato spostato tramite script.
Per impostazione predefinita, solo gli elementi interattivi possono ricevere il focus: i link (<a href>), i controlli di form (<input>, <textarea>, <select>, <button>) e pochi altri. Per rendere qualsiasi elemento focalizzabile — un <div>, <span> o <li> — è necessario assegnargli un attributo tabindex. Usa tabindex="0" per inserirlo nell'ordine di tabulazione naturale, oppure tabindex="-1" per renderlo focalizzabile solo tramite script (element.focus()).
Un'insidia critica: focus e blur non fanno bubbling. Un listener collegato a un elemento genitore non si attiverà quando un input discendente acquisisce il focus. Quando hai bisogno della delega degli eventi su un contenitore, usa invece gli equivalenti con bubbling focusin e focusout — si comportano in modo identico ma si propagano verso l'alto nell'albero DOM.
focus vs. blur vs. focusin vs. focusout
| Evento | Si attiva quando | Fa bubbling? |
|---|---|---|
focus | l'elemento acquisisce il focus | No |
blur | l'elemento perde il focus | No |
focusin | l'elemento acquisisce il focus | Sì |
focusout | l'elemento perde il focus | Sì |
Per un singolo elemento noto, focus/blur sono la scelta più semplice. Per un intero form o un elenco di campi, collega focusin/focusout una sola volta sul contenitore.
Come implementare gli eventi focus
Per usare l'evento focus, collega un listener all'elemento. L'esempio seguente evidenzia un input nel momento in cui acquisisce il focus:
<input type="text" id="nameInput" placeholder="Enter Your Name">
<script>
document.getElementById('nameInput').addEventListener('focus', function(event) {
event.target.style.backgroundColor = 'lightblue';
});
</script>Questo frammento di codice rende lo sfondo del campo di input celeste quando è in focus, migliorando l'interfaccia utente indicando dove l'utente sta digitando. Per uno stile semplice, considera l'uso della pseudo-classe CSS `:focus` come alternativa standard senza JavaScript:
input:focus {
background-color: lightblue;
}Come implementare gli eventi blur
La validazione tramite blur è uno degli usi più comuni di questi eventi: si lascia all'utente il tempo di finire di digitare, poi si controlla il valore quando sposta il focus altrove. Ecco come validare un indirizzo email quando l'input perde il focus:
<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>Questo script verifica se l'email inserita corrisponde a un formato email standard e avvisa l'utente se l'input non è valido. Il colore di sfondo diventa verde se valido e salmone in caso contrario, fornendo un feedback visivo immediato.
Impostare il focus tramite script
Oltre a reagire agli eventi, puoi spostare il focus manualmente con element.focus() e rimuoverlo con element.blur(). Questo è utile per portare il cursore al primo campo al caricamento della pagina, oppure per restituire il focus a un campo non valido dopo la validazione.
<input id="search" placeholder="Search..." />
<button id="go">Focus the search box</button>
<script>
document.getElementById('go').addEventListener('click', () => {
document.getElementById('search').focus();
});
</script>Due utili aggiuntivi:
document.activeElementrestituisce sempre l'elemento che ha attualmente il focus (o<body>se nessuno ce l'ha). È comodo per verificare lo stato del focus senza listener.focus({ preventScroll: true })imposta il focus su un elemento senza scorrere la pagina per portarlo in vista — utile quando gestisci lo scroll manualmente.
Per un campo che deve ricevere il focus non appena la pagina si carica, l'attributo HTML autofocus (<input autofocus>) è l'opzione dichiarativa senza JavaScript.
Usare focusin/focusout per la delega
Poiché focus e blur non fanno bubbling, collegare un solo listener a un form non intercetterà i cambiamenti di focus sui suoi input. Gli eventi con bubbling focusin/focusout risolvono questo problema — è possibile gestire ogni campo da un singolo listener sul genitore:
<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>L'evento focusout espone anche event.relatedTarget — l'elemento che riceverà il focus successivamente — consentendo di sapere dove sta andando il focus.
Tecniche avanzate: gestione di più campi
Quando un utente compila correttamente un campo del form, puoi spostare automaticamente il focus all'input successivo non appena il corrente perde il focus. Questo semplifica la compilazione del form eliminando la necessità di clic manuali. Ecco come implementare questo 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>Questo esempio sposta automaticamente il focus al campo lastName una volta inserito un nome valido, migliorando l'esperienza utente riducendo la necessità di clic manuali.
Chiamare
input.focus()dall'interno di un handlerblurpuò creare conflitti con l'utente. Se stava cercando di cliccare su un altro elemento, rimettere il focus sul campo può sembrare una trappola. Usa questo pattern con parsimonia e preferisci mostrare un messaggio di errore che l'utente può correggere a suo ritmo.
Errori comuni
- Non aspettarti che
focus/blurfacciano bubbling. Un listener su un contenitore perfocusnon si attiverà mai; passa afocusin/focusoutper la delega. blursi esegue prima che il clic su un altro controllo sia completato. Se un handlerblurnasconde o rimuove un elemento su cui l'utente ha appena cliccato, il clic potrebbe non essere registrato — controlla primaevent.relatedTarget.- Gli elementi nascosti o con
display:nonenon possono ricevere il focus.element.focus()non produce alcun effetto su di essi. - Forzare il focus può danneggiare l'accessibilità quando è inaspettato. Mantieni l'ordine di tabulazione da tastiera prevedibile ed evita di intrappolare il focus.
- Per lo stile visivo del focus, preferisci le pseudo-classi CSS
:focus/:focus-visiblerispetto a JavaScript — non richiedono listener e funzionano anche con la navigazione solo da tastiera.
Conclusione
Gli eventi focus e blur sono la spina dorsale dei form interattivi e accessibili. Sapere che focus/blur non fanno bubbling (mentre focusin/focusout sì), come spostare il focus con element.focus(), e dove tracciare il confine tra JavaScript e la pseudo-classe CSS :focus ti permette di creare esperienze di input reattive senza sorprendere i tuoi utenti.
In seguito, esplora le interazioni correlate del browser: gli eventi da tastiera, gli eventi change, input, cut, copy, paste e il bubbling e capturing per la delega.