W3docs

Eventos focus y blur en JavaScript

Aprende cómo funcionan los eventos focus y blur en JavaScript, en qué se diferencian de focusin y focusout, y cómo usarlos para validación de formularios y accesibilidad.

JavaScript te ofrece un control preciso sobre qué elemento está actualmente enfocado — el elemento que recibe la entrada del teclado. Los eventos focus y blur te permiten reaccionar en el momento en que un elemento gana o pierde el foco, lo cual es la base para la validación de formularios en línea, resaltar el campo activo, construir widgets accesibles con el teclado y guiar a los usuarios a través de un formulario. Este artículo explica qué son estos eventos, en qué se diferencian de sus equivalentes con burbujeo focusin/focusout, y varios patrones prácticos.

Esta página se basa en la introducción a los eventos del navegador. Si necesitas gestionar eventos en muchos elementos a la vez, también lee sobre burbujeo y captura.

Entendiendo focus y blur en JavaScript

El evento focus se dispara cuando un elemento se convierte en el objetivo activo de la entrada de teclado — el elemento al que apunta document.activeElement. El evento blur se dispara cuando ese elemento pierde el foco, por ejemplo porque el usuario hace clic en otro lugar, presiona Tab, o el foco se mueve mediante programación.

Por defecto, solo los elementos interactivos pueden recibir el foco: enlaces (<a href>), controles de formulario (<input>, <textarea>, <select>, <button>) y algunos otros. Para hacer que cualquier elemento sea enfocable — un <div>, <span> o <li> — asígnale un atributo tabindex. Usa tabindex="0" para incluirlo en el orden de tabulación natural, o tabindex="-1" para que solo sea enfocable mediante script (element.focus()).

Un aspecto crítico a tener en cuenta: focus y blur no burbujean. Un listener adjunto a un elemento padre no se activará cuando un input descendiente gane el foco. Cuando necesites delegación de eventos en un contenedor, usa en su lugar los equivalentes con burbujeo focusin y focusout — se comportan de forma idéntica pero se propagan hacia arriba en el árbol DOM.

focus vs. blur vs. focusin vs. focusout

EventoSe dispara cuando¿Burbujea?
focusel elemento gana el focoNo
blurel elemento pierde el focoNo
focusinel elemento gana el foco
focusoutel elemento pierde el foco

Para un único elemento conocido, focus/blur son los más simples. Para un formulario completo o una lista de campos, adjunta focusin/focusout una sola vez en el contenedor.

Cómo implementar eventos focus

Para usar el evento focus, adjunta un listener al elemento. El siguiente ejemplo resalta un input en el momento en que gana el 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 fragmento de código hace que el fondo del campo de entrada se vuelva azul claro cuando está enfocado, mejorando la interfaz de usuario al indicar dónde está escribiendo el usuario actualmente. Para estilos simples, considera usar la pseudo-clase CSS `:focus` como alternativa estándar sin JavaScript:

input:focus {
  background-color: lightblue;
}

Cómo implementar eventos blur

Validar en blur es uno de los usos más comunes de estos eventos: dejas que el usuario termine de escribir y luego compruebas el valor cuando sale del campo. Así se valida una dirección de correo electrónico cuando el input pierde el 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 comprueba si el correo electrónico introducido coincide con un formato de email estándar y alerta al usuario si la entrada no es válida. El color de fondo cambia a verde si es válido y a salmón si no lo es, proporcionando retroalimentación visual inmediata.

Enfocar elementos mediante script

Más allá de reaccionar a eventos, puedes mover el foco tú mismo con element.focus() y eliminarlo con element.blur(). Esto es útil para enviar el cursor al primer campo al cargar la página, o para devolver el foco a un campo inválido tras la validación.

<input id="search" placeholder="Search..." />
<button id="go">Focus the search box</button>
<script>
  document.getElementById('go').addEventListener('click', () => {
    document.getElementById('search').focus();
  });
</script>

Dos extras útiles:

  • document.activeElement siempre devuelve el elemento que actualmente tiene el foco (o <body> si ninguno lo tiene). Es muy útil para comprobar el estado del foco sin listeners.
  • focus({ preventScroll: true }) enfoca un elemento sin desplazarse hasta él — útil cuando gestionas el scroll tú mismo.

Para un campo que debe estar enfocado en cuanto se cargue la página, el atributo HTML autofocus (<input autofocus>) es la opción declarativa sin JavaScript.

Usar focusin/focusout para delegación

Como focus y blur no burbujean, adjuntar un único listener a un formulario no detectará los cambios de foco en sus inputs. Los eventos con burbujeo focusin/focusout resuelven esto — puedes gestionar todos los campos desde un único listener en el padre:

<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>

El evento focusout también expone event.relatedTarget — el elemento que recibirá el foco a continuación — lo que te permite saber hacia dónde va el foco.

Técnicas avanzadas: gestión de múltiples campos

Cuando un usuario completa correctamente un campo del formulario, puedes desplazar automáticamente el foco al siguiente input al salir del campo actual. Esto agiliza el relleno del formulario eliminando la necesidad de clics manuales. Así se implementa este comportamiento:

<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 ejemplo desplaza automáticamente el foco al campo lastName una vez que se introduce un nombre válido, mejorando la experiencia de usuario al reducir la necesidad de clics manuales.

Llamar a input.focus() desde dentro de un handler de blur puede generar conflictos con el usuario. Si estaban intentando hacer clic en un elemento diferente, volver a enfocar el campo puede sentirse como una trampa. Usa este patrón con moderación y prefiere mostrar un mensaje de error que el usuario pueda corregir a su propio ritmo.

Errores comunes

  • No esperes que focus/blur burbujeen. Un listener en un contenedor para focus nunca se disparará; cambia a focusin/focusout para delegación.
  • blur se ejecuta antes de que se complete el clic en otro control. Si un handler de blur oculta o elimina un elemento en el que el usuario acaba de hacer clic, es posible que ese clic no se registre — comprueba event.relatedTarget primero.
  • Los elementos ocultos o con display:none no pueden recibir el foco. element.focus() no hace nada en ellos de forma silenciosa.
  • Forzar el foco perjudica la accesibilidad cuando es inesperado. Mantén el orden de tabulación del teclado predecible y evita atrapar el foco.
  • Para el estilo visual del foco, prefiere las pseudo-clases CSS :focus / :focus-visible sobre JavaScript — no requieren listeners y funcionan en la interacción solo con teclado.

Conclusión

Los eventos focus y blur son la columna vertebral de los formularios interactivos y accesibles. Saber que focus/blur no burbujean (y que focusin/focusout sí lo hacen), cómo mover el foco con element.focus(), y dónde trazar la línea entre JavaScript y la pseudo-clase CSS :focus te permitirá crear experiencias de entrada responsivas sin sorprender a tus usuarios.

A continuación, explora interacciones relacionadas del navegador: eventos de teclado, los eventos change, input, cut, copy, paste, y burbujeo y captura para delegación.

Práctica

Práctica
¿Cuáles de las siguientes afirmaciones son correctas sobre los eventos focus y blur en JavaScript?
¿Cuáles de las siguientes afirmaciones son correctas sobre los eventos focus y blur en JavaScript?
Was this page helpful?