Al desarrollar aplicaciones, los proveedores de front-end rara vez prestan atención a cómo usará el usuario las funciones del teclado proporcionadas por el navegador. No soy una excepción, pero un día me dieron una tarea sobre UX y transiciones presionando "Tab" y "Shift + Tab".
La esencia de la tarea es transparente y limpia: hay una interfaz, cuyo diseño se muestra a continuación. Conceptualmente, 1 página puede contener 2 formularios diferentes y el requisito era que "ejecutar con pestañas no va de un formulario a otro".

Todo estaría bien si el navegador supiera cómo bloquear de forma "nativa" el enfoque en los formularios. En la figura siguiente se presenta un ejemplo, donde el "borde" naranja marca el elemento actual y el gris, el anterior.


Como puede ver, el comportamiento "nativo" no cumple los requisitos. Entonces, resolvamos este problema. La solución no es complicada, así que considérelo.
Sería ideal si hubiera algunas "compuertas" que evitarían "saltar" fuera del foco desde el último elemento (con "Tab") o el primer elemento (con "Shift + Tab") con
"tabindex" o foco de apoyo por defecto. Entonces, la esencia es simple: nuestras "puertas" son "elementos de entrada" ocultos, que reciben un evento de "evento" como argumento durante el evento "onFocus" y devuelven el foco al elemento del que proviene. Ilustración a continuación.

Obtener el elemento anterior es factible utilizando la propiedad "relatedTarget" del objeto "event". Visualización de la solución a continuación.


Y aquí está el código en sí. Vale la pena señalar que no hay una sintaxis "ES6 +", ya que la idea de admitir el código con diferentes navegadores sin conectar varios "transpiladores" como Babel es fundamental.
function getGateInput(handleTabOut) { var input = document.createElement("input");
No hay nada complicado: se crea una "entrada", se establecen estilos que "ocultan" nuestras "puertas". Aquí, "display: none" no se usa, ya que el navegador no enfoca "Tabs" en tales elementos. Debido a este comportamiento, es necesario hacer que el elemento sea transparente y moverlo fuera de la ventana del navegador.
function getTabOutHandler(element, GATES) { return function(event) { var relatedTarget = event.relatedTarget || event.fromElement; var target = event.target; var gatesTrapped = target === GATES[0] || target === GATES[1]; if (gatesTrapped && isChild(relatedTarget, element)) { event.preventDefault(); relatedTarget.focus(); } }; }
Para devolver el foco al elemento anterior, use getTabOutHandler. Este es
el HOC . Su primer argumento es nuestro contenedor (alrededor del cual configuramos la "puerta"), y el segundo espera una matriz de "puertas" que creamos usando getGateInput. Esta función devuelve un controlador de eventos que funciona de acuerdo con el principio descrito anteriormente.
Para que el foco entre en el contenedor, necesitamos abrir y cerrar la "puerta". Haremos esto configurando el atributo
"tabindex" . (-1 - no enfocar con pestañas, 0 - enfocar según la secuencia)
function moveGates(open, GATES) { GATES[0].setAttribute("tabindex", open ? -1 : 0); GATES[1].setAttribute("tabindex", open ? -1 : 0); }
Para controlar las puertas, configuraremos un controlador que "escuchará" presionar Tab (código 9) y si el elemento enfocado (activeElement) está dentro del contenedor, entonces cierre la "puerta", de lo contrario ábralo.
window.addEventListener("keydown", function(event) { if (event.keyCode === 9) { if (isChild(document.activeElement, element)) { moveGates(false, GATES); } else { moveGates(true, GATES); } } });
Total
Se consideró un método para bloquear el foco en un formulario, que consiste en devolver el foco a un elemento enfocado anterior. Para "captar" el foco, utilizamos "elementos de entrada" ocultos, cuyo foco se controlaba utilizando el
"índice tabin" . El código anterior es parte de la biblioteca
tab-out-catcher que escribí para resolver mi problema. Ejemplos de uso se pueden encontrar
aquí . También hay una
solución para las aplicaciones React.