Melhorando o UX com a tecla Tab

Ao desenvolver aplicativos, os fornecedores front-end raramente prestam atenção em como o usuário usará as funções do teclado fornecidas pelo navegador. Não sou uma exceção, mas um dia recebi uma tarefa referente a UX e transições pressionando “Tab” e “Shift + Tab”.

A essência da tarefa é transparente e limpa: existe uma interface cujo layout é exibido abaixo. Conceitualmente, uma página pode conter 2 formulários diferentes e o requisito era que “executar com guias não vá de 1 formulário para outro”.

imagem

Tudo ficaria bem se o navegador soubesse "bloquear" nativamente o foco nos formulários. Um exemplo é apresentado na figura abaixo, onde a “borda” laranja marca o elemento atual e cinza - o anterior.

imagem

Como você pode ver, o comportamento "nativo" não atende aos requisitos. Então, vamos resolver esse problema. A solução não é complicada, então considere-a.

Seria ideal se houvesse alguns "portões" que impediriam o "pulo" de foco do último (com "Tab") ou do primeiro (com "Shift + Tab") elemento com "tabindex" ou suporte ao foco por padrão. Portanto, a essência é simples: nossos “portões” são “elementos de entrada” ocultos, que recebem um evento de “evento” como argumento durante o evento “onFocus” e retornam o foco ao elemento de origem. Ilustração abaixo.

imagem

É possível obter o elemento anterior usando a propriedade "relatedTarget" do objeto "event". Visualização da solução abaixo.

imagem

E aqui está o próprio código. Vale ressaltar que não há sintaxe "ES6 +", pois a idéia é oferecer suporte ao código com diferentes navegadores sem conectar diferentes "transpilers" como o Babel.

function getGateInput(handleTabOut) { var input = document.createElement("input"); // not visibiliy:hidden or display:none as need to focus on this element var hiddingStyle = "opacity: 0;cursor: none;position: absolute;top: -10px;left: -10px;"; input.setAttribute("style", hiddingStyle); input.addEventListener("focus", handleTabOut); return input; } 

Não há nada complicado: é criada uma "entrada", são definidos estilos que "escondem" nossos "portões". Aqui, "display: none" não é usado, pois o navegador não focaliza "Guias" nesses elementos. Devido a esse comportamento, é necessário tornar o elemento transparente e movê-lo para fora da janela do 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 retornar o foco ao item anterior, use getTabOutHandler. Este é o HOC . Seu primeiro argumento é o nosso contêiner (aquele em torno do qual definimos o "portão"), e o segundo espera uma matriz de "portão" que criamos usando getGateInput. Essa função retorna um manipulador de eventos que funciona de acordo com o princípio descrito acima.

Para que o foco entre no contêiner, precisamos abrir e fechar o “portão”. Faremos isso configurando o atributo "tabindex" . (-1 - não foque com Guias, 0 - foque de acordo com o fluxo)

 function moveGates(open, GATES) { GATES[0].setAttribute("tabindex", open ? -1 : 0); GATES[1].setAttribute("tabindex", open ? -1 : 0); } 

Para controlar os portões, configuraremos um manipulador que "ouvirá" pressionar Tab (código 9) e se o elemento em foco (activeElement) estiver dentro do contêiner, feche o "portão", caso contrário, abra-o.

 window.addEventListener("keydown", function(event) { if (event.keyCode === 9) { if (isChild(document.activeElement, element)) { moveGates(false, GATES); } else { moveGates(true, GATES); } } }); 

Total


Foi considerado um método para bloquear o foco em um formulário, que consiste em retornar o foco a um elemento focalizado anterior. Para "capturar" o foco, usamos "elementos de entrada" ocultos, cujo foco foi controlado usando o "tabindex" . O código acima faz parte da biblioteca tab-out-catcher que escrevi para resolver meu problema. Exemplos de uso podem ser encontrados aqui . Há também uma solução para aplicativos React.

Source: https://habr.com/ru/post/pt469749/


All Articles