Eventos e páginas interativas

Faça páginas web responderem às pessoas. Aprenda a registrar ouvintes de eventos, ler o objeto de evento e acompanhar o borbulhamento dos eventos pela página para que um ouvinte possa tratar eventos de vários elementos. Trate o pressionamento de teclas, cliques, toques e entradas de caneta, construa uma interação de arraste, leia e envie formulários em JavaScript e valide entradas com as regras nativas do navegador e suas próprias mensagens. Termine construindo controles personalizados que funcionem com teclado e leitor de tela, além de mouse.

BásicoAula 6 de 9 do curso Curso de Programação em JavaScript

O que você vai aprender

  1. Faça uma página reagir quando algo acontecer: registre ouvintes em elementos, leia o que o objeto de evento informa e decida por quanto tempo cada ouvinte permanece ativo.
    • Registrar um ouvinte de evento em um elemento
      Use addEventListener para executar uma função sempre que ocorrer um clique, pressionamento de tecla, ação de formulário ou evento de página em um elemento.
    • Ler as informações do objeto de evento
      Use o objeto de evento recebido por um ouvinte para descobrir o que aconteceu e onde: seu tipo, alvo, alvo atual e detalhes específicos do evento.
    • Remover ouvintes e controlar sua execução
      Pare de ouvir quando um ouvinte não for mais necessário, use as opções once, signal e passive e dispare seus próprios eventos personalizados.
  2. Explique como um evento desce até seu alvo e volta a subir pela página, cancele o comportamento nativo do navegador quando substituí-lo e use o borbulhamento para tratar eventos de vários elementos com um ouvinte.
    • Explicar o borbulhamento e a captura
      Descreva as três fases da propagação de eventos e preveja a ordem em que ouvintes em elementos aninhados são executados.
    • Impedir ações padrão e interromper a propagação
      Cancele a resposta nativa do navegador a um evento quando seu código a substituir e interrompa a propagação de um evento apenas quando isso for realmente necessário.
    • Tratar eventos de vários elementos com delegação de eventos
      Use um ouvinte em um ancestral comum e event.target.closest() para tratar eventos de vários elementos filhos, incluindo elementos adicionados posteriormente.
  3. Reaja ao pressionamento de teclas, mudanças de foco, cliques, toques e entradas de caneta e construa uma interação de arraste que funcione com todo tipo de ponteiro.
    • Responder ao pressionamento de teclas e às mudanças de foco
      Use keydown, keyup e os eventos de foco, escolha entre event.key e event.code e crie atalhos de teclado que não atrapalhem o usuário.
    • Tratar cliques, toques e entradas de caneta com eventos de ponteiro
      Use click para ativação e eventos de ponteiro para pressionar, mover e soltar com mouse, dedo ou caneta; leia coordenadas e botões; e escolha os eventos adequados para a passagem do ponteiro.
    • Construir uma interação de arraste com eventos de ponteiro
      Combine pointerdown, pointermove e pointerup com captura de ponteiro para mover um elemento, fazê-lo funcionar em telas sensíveis ao toque e oferecer uma forma de fazer o mesmo sem arrastar.
  4. Leia o que os usuários inserem enquanto digitam, trate o envio de formulários em JavaScript e verifique as entradas com os recursos de validação do navegador e suas próprias regras, com mensagens de erro claras.
    • Ler campos de formulário e responder à digitação dos usuários
      Leia campos de texto, números, caixas de seleção, botões de opção e listas de seleção, use os eventos input e change nos momentos adequados e colete um formulário inteiro com FormData.
    • Tratar o envio de formulários em JavaScript
      Ouça o evento submit do formulário, impeça o recarregamento da página, leia os dados enviados e saiba o que aciona um envio.
    • Usar a validação nativa do navegador
      Descreva regras com atributos HTML, leia o resultado no objeto validity, verifique campos por meio de código e estilize campos inválidos no momento adequado.
    • Escrever validação personalizada com mensagens de erro claras
      Adicione regras que os atributos HTML não conseguem expressar, escreva mensagens úteis, mostre-as no momento adequado e associe-as aos seus campos.
  5. Crie elementos interativos que funcionem com mouse, teclado e leitor de tela: prefira HTML nativo, adicione papéis, suporte ao teclado e estado ao construir seus próprios controles e mantenha o foco onde os usuários esperam.
    • Preferir elementos nativos e permitir que controles personalizados recebam foco
      Saiba o que os elementos interativos nativos oferecem automaticamente e o que um controle personalizado construído com um <div> ou <span> precisa acrescentar: um papel, capacidade de receber foco, um nome acessível e um indicador de foco visível.
    • Adicionar suporte ao teclado e estado aos controles personalizados
      Faça botões personalizados, botões de alternância, controles de expansão e recolhimento, caixas de seleção e grupos de itens funcionarem pelo teclado e mantenha seu estado ARIA sincronizado com o que os usuários veem.
    • Manter o foco onde os usuários esperam quando a página mudar
      Mova o foco intencionalmente quando o conteúdo for aberto, fechado ou removido ou mostrar erros, e nunca o mova de forma inesperada enquanto os usuários estiverem digitando ou escolhendo.

Guia de estudo de Eventos e páginas interativas

5 capítulos

1

Responder a eventos com ouvintes de eventos

Páginas web respondem por meio de funções registradas para eventos. A configuração escolhe o elemento e o tipo de evento; cada ocorrência posterior traz um objeto de evento que descreve o que aconteceu. Ler esse objeto permite que um ouvinte atue no controle correto, mesmo quando um clique atinge um ícone dentro dele. Referências e opções de ouvintes permitem que um recurso mantenha suas respostas ativas exatamente pelo tempo necessário, e eventos personalizados permitem que uma parte da página notifique outra.

1.1 Ouvintes transformam ações em código

Uma página pode esperar que uma pessoa aja. Um evento informa algo que aconteceu, e um ouvinte de evento é a função chamada em resposta. Registrar um ouvinte configura essa resposta; não executa a ação imediatamente.

Adicione a função ao elemento

Selecione um elemento que já exista, escolha o nome exato do evento e passe uma função:

const button = document.querySelector("#like");
let likes = 0;
button.addEventListener("click", function () {
  likes = likes + 1;
  button.textContent = "Likes: " + likes;
});

A seleção, a configuração da variável e o registro são executados quando o script é executado. Cada clique posterior executa o corpo da função. Após três cliques, o botão mostra “Likes: 3”. Manter likes fora da função preserva o total entre cliques; colocar let likes = 0 dentro dela o reiniciaria a cada vez.

Passe uma referência à função, como showMenu, sem parênteses. Em button.addEventListener("click", showMenu()), o JavaScript chama showMenu imediatamente e passa seu valor de retorno como ouvinte. Para fornecer um argumento mais tarde, envolva a chamada: button.addEventListener("click", () => showMenu("main"));.

Escolha um evento que realmente ocorra

Nomes são cadeias de caracteres que diferenciam maiúsculas de minúsculas e não têm o prefixo “on”. Use "click", não "Click" ou "onclick". Um nome inventado é aceito sem erro, mas o navegador não o emitirá para um clique. Famílias comuns incluem eventos de ponteiro, como pointerdown e pointerup, eventos de teclado, como keydown, eventos de formulário, como input e submit, e eventos de foco, como focusin. DOMContentLoaded tem sua própria grafia exata de maiúsculas e minúsculas.

Configure o elemento certo no momento certo

Um script no cabeçalho pode ser executado antes de um botão existir. Nesse caso, a seleção retorna null, e chamar addEventListener nele lança um erro. Carregue um script externo com defer, coloque-o após a marcação ou registre a configuração no evento DOMContentLoaded do documento. Um elemento criado posteriormente precisa de configuração após a criação ou de um ouvinte em um ancestral.

querySelectorAll retorna uma NodeList, não um único alvo de evento. Registre ouvintes em seus elementos:

document.querySelectorAll(".tab").forEach((tab) => {
  tab.addEventListener("click", selectTab);
});
Permita que ouvintes coexistam
MétodoO que o registro faz
addEventListener("click", fn)Adiciona um ouvinte junto aos demais e aceita opções.
button.onclick = fnSubstitui o único tratador da propriedade; atribua null para removê-lo.
Um atributo HTML onclickColoca JavaScript dentro da marcação.

Ouvintes com a mesma configuração de captura são executados na ordem de registro. No alvo do evento, ouvintes de captura são executados antes dos ouvintes que não usam captura. Adicionar novamente o mesmo objeto de função com o mesmo tipo e configuração de captura não adiciona uma segunda cópia.

Principais conclusões

  • Passe a própria função; use uma função envoltória quando a chamada posterior precisar de argumentos.
  • Nomes de eventos exigem grafia exata, incluindo maiúsculas e minúsculas.
  • Um elemento deve existir quando seu ouvinte é registrado.
  • Percorra uma NodeList para registrar ouvintes em seus elementos.
  • addEventListener permite vários ouvintes; uma propriedade de tratamento armazena um.

1.2 Identifique onde um evento começou

O navegador passa um objeto de evento ao seu ouvinte. Suas propriedades explicam o evento que acionou essa chamada específica. Nomeie o parâmetro event ou e; a escolha é sua.

button.addEventListener("click", (event) => {
  console.log(event.type);
  console.log(event.currentTarget);
});

Isso registra "click" e o botão durante a chamada do ouvinte. Registrar o objeto inteiro pode ajudar você a descobrir suas outras propriedades.

Distinga a origem do ouvinte

Imagine um botão que contém uma imagem:

<button id="save" data-id="7">
  <img src="disk.svg" alt=""> Save
</button>
PropriedadeSignificadoQuando a imagem é clicada
event.targetOnde o evento começouA imagem
event.currentTargetOnde o ouvinte em execução foi registradoO botão, para um ouvinte no botão

Clicar no texto “Save” também torna o botão o alvo. O texto é parte do botão; ele não se torna um elemento alvo separado.

Essa diferença importa ao ler dados. A imagem não tem o data-id do botão, então event.target.dataset.id é undefined em um clique na imagem. Um ouvinte registrado diretamente no botão pode ler event.currentTarget.dataset.id. Um ouvinte em um contêiner maior pode encontrar o botão desejado com event.target.closest("button") e verificar se há uma correspondência.

Leia os detalhes deste evento

Todo evento tem um type, um target e um currentTarget. O booleano bubbles informa se ele volta a subir pelos ancestrais. cancelable informa se o código pode cancelar sua ação padrão, e defaultPrevented registra se esse cancelamento ocorreu. timeStamp registra o momento de criação do evento em milissegundos em relação à origem de tempo da página.

Diferentes famílias de eventos acrescentam detalhes úteis. Um click moderno fornece um PointerEvent, que herda propriedades de eventos de mouse, como clientX, clientY e button. Um KeyboardEvent acrescenta key, code e indicadores de teclas modificadoras. Um ouvinte de input pode usar event.target.value para ler o novo texto do campo.

Para um ouvinte em uma galeria, event.target.tagName pode ser "IMG" quando uma foto é clicada ou "DIV" quando o espaço entre fotos é clicado. Trate o caso efetivamente informado. Não suponha que todo evento dentro de um contêiner veio do mesmo tipo de filho.

Use o valor enquanto o ouvinte é executado

Em um ouvinte definido com uma função comum, this é igual a event.currentTarget. Uma função de seta obtém this do código ao redor; ela não recebe o elemento como this. Usar event.currentTarget funciona com ambos os estilos de função.

Após o disparo, currentTarget é redefinido para null. Um console pode mostrar esse valor posterior quando você expande um evento registrado anteriormente. Registre event.currentTarget diretamente dentro do ouvinte para inspecionar o elemento durante a chamada.

Principais conclusões

  • target identifica a origem do evento; currentTarget identifica o elemento do ouvinte em execução.
  • Leia os dados do elemento que realmente os possui.
  • Famílias de eventos acrescentam propriedades como coordenadas, valores de teclas e modificadores.
  • currentTarget está disponível durante a execução do ouvinte e depois se torna null.

1.3 Controlar a duração de um ouvinte

Um ouvinte deve permanecer ativo enquanto seu recurso precisar dele. Para uma interação temporária com o teclado, mantenha a referência à função para que ela possa ser removida quando a interação for encerrada.

Remova a mesma função
function onKey(event) {
  console.log(event.key);
}
document.addEventListener("keydown", onKey);
// When the feature closes:
document.removeEventListener("keydown", onKey);

A remoção compara o tipo de evento, o objeto de função e a configuração de captura. Uma função anônima também pode ser removida quando sua referência é salva, como em const handler = () => save();. Escrever uma nova () => save() na chamada de remoção cria uma função diferente, mesmo que o código pareça idêntico.

Escolha as opções de registro
OpçãoEfeito
once: trueRemove este ouvinte após sua primeira chamada.
signal: controller.signalRemove o ouvinte quando esse controlador é cancelado.
capture: trueOuve no caminho de captura.
passive: trueIndica que o ouvinte não cancelará a ação padrão.

Um banner de boas-vindas exibido uma única vez pode usar { once: true }. Um recurso com vários ouvintes pode atribuir a eles um único sinal:

const controller = new AbortController();
window.addEventListener("pointermove", moveCursor, {
  signal: controller.signal
});
window.addEventListener("keydown", onKey, {
  signal: controller.signal
});
// Close the feature:
controller.abort();

O cancelamento remove os dois registros. Um controlador cancelado não pode ser redefinido; crie um novo controlador para um novo período de uso. Para remoção com removeEventListener, repita capture: true se ele tiver sido usado no registro. once, signal e passive não fazem parte dos critérios de correspondência para remoção.

Uma chamada a preventDefault() em um ouvinte passivo é ignorada. Os navegadores costumam tornar passivos por padrão certos ouvintes relacionados à rolagem em alvos no nível do documento, incluindo wheel, touchstart e touchmove; use explicitamente { passive: false } nesses casos quando for necessário cancelar.

Evite acumular funções de retorno

Se cada clique em “Iniciar” adicionar um novo ouvinte anônimo ao tabuleiro, iniciar duas vezes fará um clique no tabuleiro executar duas funções de retorno. Registre o ouvinte do tabuleiro uma vez, reutilize o mesmo objeto de função ou cancele o grupo anterior antes de substituí-lo. Funções de retorno once distintas ainda podem se acumular antes de serem executadas.

Desconectar um elemento preserva seus ouvintes. Eles funcionam se o elemento for reinserido, e dispatchEvent() pode alcançá-los enquanto ele estiver desconectado. O elemento pode ser recolhido pelo coletor de lixo quando ele e seus ouvintes não puderem mais ser alcançados. Um ouvinte em window ou document permanece registrado até ser removido explicitamente.

Dispare um evento personalizado
const event = new CustomEvent("cart:add", {
  detail: { id: 42 },
  bubbles: true
});
item.dispatchEvent(event);

Os ouvintes leem event.detail.id. O disparo chama os ouvintes imediatamente, antes de retornar. bubbles: true permite que os ancestrais também o recebam. Um evento enviado com dispatchEvent() tem isTrusted igual a false; eventos disparados pelo navegador podem ser confiáveis mesmo quando causados por uma API como focus().

Principais conclusões

  • A remoção compara o tipo, a identidade da função e a configuração de captura.
  • once encerra um registro após uma chamada; cancelar um sinal encerra seus registros associados.
  • Um ouvinte passivo não pode cancelar uma ação padrão.
  • Novas funções de retorno adicionadas a cada configuração podem se acumular.
  • Desconectar um elemento preserva seus ouvintes.
  • Eventos personalizados carregam dados em detail e são disparados de forma síncrona.
2

Acompanhar a propagação dos eventos pela página

Elementos aninhados compartilham um caminho de evento. Um clique pode passar por um contêiner antes de chegar ao alvo e visitá-lo novamente durante o borbulhamento, o que faz um ouvinte ser suficiente para uma lista que muda. Acompanhar esse caminho ajuda a explicar por que uma ação em um filho também aciona um pai. Distinga o cancelamento do comportamento do navegador do controle da propagação e use a origem do evento para escolher quais ações um ouvinte compartilhado deve tratar.

2.1 O caminho de um evento por elementos aninhados

Um clique dentro de um botão também pode ser recebido pelos ancestrais do botão. Propagação é o percurso do evento pela árvore do documento. Acompanhar esse percurso explica tanto os ouvintes compartilhados úteis quanto as ações adicionais inesperadas.

Acompanhe três fases
  1. Captura: o evento percorre o caminho de window para baixo, pelos ancestrais, em direção ao alvo.
  2. Alvo: ouvintes são executados no elemento onde o evento começou.
  3. Borbulhamento: um evento que borbulha volta a subir pelos ancestrais até window.

A propriedade eventPhase informa 1 para captura, 2 no alvo e 3 para borbulhamento. Um ouvinte registrado sem opções é executado no alvo ou no caminho de borbulhamento. Um ouvinte com { capture: true } é executado no caminho de descida, inclusive no alvo se estiver registrado nele.

Rastreie um clique concreto
<div id="outer">
  <div id="inner">
    <button>Go</button>
  </div>
</div>

Suponha que o botão e cada div tenham ouvintes de clique comuns que registram seus nomes. Clicar em “Go” registra “button”, “inner” e depois “outer”. Clicar em uma área vazia de inner registra “inner” e depois “outer”; o botão não está no caminho desse evento.

Agora adicione um ouvinte de captura a outer. Um clique no botão registra primeiro “outer (capture)”, depois “button”, “inner” e “outer” pelos ouvintes comuns. O ouvinte de captura vê o clique antes dos descendentes. Após outer, o evento pode continuar por body, html, document e window se houver ouvintes registrados nesses elementos.

É um único evento, não um novo clique criado em cada ancestral. target permanece sendo o botão durante todo o percurso. currentTarget muda conforme cada ouvinte é executado. No ouvinte externo, ler target ainda identifica o botão original.

Verifique quais eventos borbulham
BorbulhaNão borbulha
click, input, change, submitinvalid
keydown, pointerdownfocus, blur
focusin, focusoutpointerenter, pointerleave
pointerover, pointeroutmouseenter, mouseleave

A propriedade bubbles do evento informa se ele tem uma fase de borbulhamento. Eventos que não borbulham ainda podem ser observados por um ouvinte de captura em um ancestral. Para tratar mudanças de foco por meio de um ouvinte comum no contêiner, escolha focusin ou focusout.

Explique um erro de ação aninhada

Um cartão de produto abre uma visão de detalhes quando clicado. Seu botão “Remover” exclui o produto. Clicar nesse botão primeiro o exclui, depois alcança o ouvinte do cartão e abre a visão de detalhes. O caminho do evento explica por que ambas as funções de retorno são executadas.

O cartão pode ignorar cliques de remoção com if (event.target.closest(".remove")) return;. Como alternativa, o botão pode interromper a propagação. Filtrar no cartão preserva o evento para outros ancestrais que possam precisar dele.

Principais conclusões

  • A propagação segue as fases de captura, alvo e depois borbulhamento para eventos que borbulham.
  • Ouvintes comuns em ancestrais recebem cliques em descendentes no caminho de subida.
  • target permanece fixo enquanto currentTarget muda.
  • Use um evento de foco que borbulha ou captura para observar o foco de um ancestral.

2.2 Cancelar uma ação ou interromper um percurso

Um ouvinte pode mudar o que acontece após um evento ou por onde o evento passa. São decisões distintas. Um evento em um link pode continuar borbulhando mesmo depois que a navegação foi cancelada.

Substitua uma ação do navegador

Uma ação padrão é um comportamento fornecido pelo navegador: seguir um link, enviar um formulário, alternar uma caixa de seleção, inserir texto, rolar com a barra de espaço ou mover o foco com Tab. Use preventDefault() quando seu código substituir essa ação:

help.addEventListener("click", (event) => {
  event.preventDefault();
  openHelpPanel();
});

Para um link para /help, isso abre o painel sem navegar. O link ainda oferece seu destino quando o JavaScript não é executado.

Somente eventos canceláveis podem ser cancelados. Inspecione event.cancelable; defaultPrevented registra o cancelamento bem-sucedido. input ocorre após a mudança do valor e não é cancelável. Chamar preventDefault() nele não remove o texto inserido. Um evento beforeinput cancelável é o lugar adequado para interceptar uma edição; cancelar um keydown relevante pode impedir o efeito padrão dessa tecla.

Controle a propagação separadamente
MétodoImpede a ação padrão do navegador?Interrompe ouvintes posteriores?
preventDefault()Sim, se o evento for cancelável e o ouvinte não for passivoNão
stopPropagation()NãoImpede o percurso para outros elementos; ouvintes neste elemento ainda são executados
stopImmediatePropagation()NãoTambém interrompe os ouvintes restantes neste elemento

Um link cujo ouvinte apenas interrompe a propagação ainda segue sua URL. Cancelar apenas a navegação ainda permite que um ouvinte de clique no documento receba o evento. Retornar false de uma função de retorno de addEventListener não faz nenhuma das duas coisas. Uma propriedade ou um atributo em linha de tratamento pode cancelar a ação padrão ao retornar false, mas isso ainda não interrompe a propagação.

Mantenha o comportamento compartilhado funcionando

Um ancestral pode fechar um menu ou contar interações. Interromper a propagação oculta o evento desse código. Muitas vezes, o ancestral pode inspecionar target ou defaultPrevented.

Por exemplo, um menu fecha apenas quando um clique ocorre fora tanto do menu quanto de seu controle de abertura:

document.addEventListener("click", (event) => {
  if (!menu.contains(event.target) &&
      !menuButton.contains(event.target)) {
    menu.hidden = true;
  }
});

contains() inclui o próprio elemento e seus descendentes. Verificar o controle de abertura é importante porque o clique que abre o menu também borbulha até o documento. Sem esse segundo teste, o menu recém-aberto fecharia imediatamente.

Cancele apenas uma ação tratada

Em um ouvinte de teclado, verifique a tecla antes de cancelar. Cancelar todas as teclas bloqueia a digitação normal e pode impedir que Tab mova o foco. Em um ouvinte passivo, o cancelamento é ignorado por completo.

Principais conclusões

  • preventDefault() cancela uma ação padrão que pode ser cancelada, preservando a propagação.
  • stopPropagation() interrompe o percurso, não a ação padrão.
  • stopImmediatePropagation() também pula os ouvintes restantes no elemento atual.
  • input ocorre tarde demais para cancelar uma edição.
  • Verificações de clique fora devem incluir o pop-up e seu controle de abertura.
  • Cancele apenas as ações específicas de teclado que seu código trata.

2.3 Um ouvinte para uma lista que muda

A delegação de eventos coloca um ouvinte em um ancestral estável e usa a origem do evento para escolher uma ação. Ela é útil quando uma lista tem muitos itens ou quando o código cria novos itens após a configuração.

Encontre o controle desejado

Um clique que borbulha chega à lista, independentemente de qual descendente foi clicado. Comece por event.target, encontre o controle correspondente mais próximo e descarte cliques não relacionados:

const list = document.querySelector("#todos");
list.addEventListener("click", (event) => {
  const button = event.target.closest(".remove");
  if (!button || !list.contains(button)) return;
  const item = button.closest("li");
  console.log("Removing item " + item.dataset.id);
  item.remove();
});

A lista contém itens como <li data-id="7">Buy milk <button class="remove">Remove</button></li>. O ouvinte pertence à lista, então um novo item com a mesma marcação funciona imediatamente após a inserção.

Acompanhe um clique em um ícone pelo código. O alvo é o ícone, closest(".remove") encontra seu botão, e button.closest("li") encontra o item. Seu data-id identifica o item na mensagem. Por fim, remove() altera a página.

Mantenha as duas verificações
TestePor que importa
!buttonUm clique em um espaço vazio da lista ou no texto comum de um item pode não encontrar um botão de remoção.
!list.contains(button)closest() pode subir além da lista e encontrar um ancestral externo correspondente.

Testar apenas event.target.matches(".remove") perde cliques no ícone porque o próprio ícone não corresponde ao seletor. closest() verifica o alvo e sobe por seus ancestrais. Em um ouvinte delegado, currentTarget é a lista; ele não se torna o botão encontrado.

Encaminhe várias ações

Atributos de dados permitem que um ouvinte de barra de ferramentas escolha entre ações conhecidas:

const actions = { bold: makeBold, italic: makeItalic,
  clear: clearText };
toolbar.addEventListener("click", (event) => {
  const button = event.target.closest("button[data-action]");
  if (!button || !toolbar.contains(button)) return;
  const action = actions[button.dataset.action];
  if (typeof action === "function") action();
});

Um botão com data-action="clear" seleciona clearText. A verificação da função trata uma ação desconhecida sem tentar chamar undefined.

Escolha um evento adequado

A delegação funciona com eventos que borbulham, além de cliques. Um único ouvinte de input no formulário pode passar event.target a uma função de verificação de campo. Para delegar mudanças de foco, use focusin ou focusout; focus e blur comuns não borbulham. Para transições de passagem do ponteiro, use eventos over/out que borbulham quando a delegação for necessária.

Uma chamada a stopPropagation() em um descendente pode impedir que um evento chegue ao contêiner. Quando um ouvinte delegado parecer inativo, verifique o tipo de evento, o alvo, a correspondência com o seletor e se algo abaixo do contêiner interrompeu o percurso.

Principais conclusões

  • Registre o ouvinte em um ancestral que permanece mesmo quando seus filhos mudam.
  • closest() encontra um controle mesmo quando um ícone aninhado é clicado.
  • Descarte resultados sem correspondência e correspondências fora do contêiner.
  • A delegação inclui automaticamente filhos correspondentes adicionados posteriormente.
  • Atributos de dados podem encaminhar um ouvinte compartilhado para ações conhecidas.
  • A delegação precisa de um evento que alcance o ancestral.
3

Tratar entradas de teclado e ponteiro

Uma interação pode ocorrer por teclas, mouse, dedo ou caneta. O evento escolhido determina se você recebe uma ativação, um valor de texto alterado ou o movimento de um ponteiro específico. Referenciais de coordenadas e posições iniciais armazenadas tornam o arraste previsível. O foco e controles alternativos mantêm a página utilizável quando uma pessoa navega pelo teclado ou não consegue realizar um gesto de arraste.

3.1 Teclas, texto e foco

A entrada do teclado vai para o elemento com foco, disponível como document.activeElement, e depois borbulha. Um ouvinte no documento pode, portanto, receber teclas de campos e de outros controles. Esse alcance torna os atalhos de teclado úteis, mas também significa que eles podem interromper a digitação.

Escolha a propriedade pelo seu significado
PropriedadeInformaExemplo
keyO valor produzido, com a disposição do teclado e os modificadores"a", "A", "Enter", " "
codeA posição física da tecla"KeyA", "Enter", "Space"

Em um teclado AZERTY, a posição identificada como Q em um teclado dos EUA produz key "a" e code "KeyQ". Use key para o significado, como Escape para fechar ou uma letra de atalho. Use code para posições fixas, como teclas de movimento em um jogo. O key da barra de espaço é um único espaço, não "Space".

keydown dispara no pressionamento inicial e pode se repetir enquanto a tecla é mantida pressionada. Chamadas repetidas têm event.repeat === true. keyup dispara quando a tecla é solta. Use keydown em vez do evento obsoleto keypress.

Trate um atalho com precisão
document.addEventListener("keydown", (event) => {
  if ((event.ctrlKey || event.metaKey) &&
      event.key.toLowerCase() === "s") {
    event.preventDefault();
    saveDraft();
  }
});

Isso trata Ctrl+S e Command+S. A conversão para minúsculas permite também "S". O cancelamento substitui a ação Salvar página do navegador apenas para o atalho correspondente. Outros indicadores de teclas modificadoras incluem shiftKey e altKey.

Para um atalho de uma única letra válido para toda a página, ignore contextos de digitação antes de agir:

if (event.target.matches("input, textarea, select") ||
    event.target.isContentEditable) return;
if (event.repeat) return;

A primeira verificação protege a entrada de texto. A segunda faz uma ação ser executada uma vez por pressionamento físico. Não cancele Tab em toda a página; é assim que usuários de teclado avançam.

Ouça o texto depois que ele mudar

Para uma tecla comum que produz um caractere imprimível, a sequência é keydown, beforeinput, input e depois keyup. Ler value em keydown fornece o valor anterior à inserção desse caractere. Use input para uma prévia de texto ou contagem de caracteres. Ele também trata edições como colagem e ditado, que não precisam de um pressionamento de tecla correspondente.

Observe mudanças de foco

focus e blur informam o recebimento e a perda de foco sem borbulhar. focusin e focusout borbulham, então um formulário pode observar seus campos por meio de um único ouvinte. relatedTarget identifica o outro elemento envolvido na mudança ou null quando não há nenhum.

password.addEventListener("focus", () => {
  hint.hidden = false;
});
password.addEventListener("blur", () => {
  hint.hidden = true;
});

A dica fica disponível quando o campo recebe foco, inclusive por Tab. Chamar element.focus() move o foco por código; a próxima entrada de teclado vai para esse elemento.

Principais conclusões

  • Use key para o significado produzido e code para a posição física.
  • Proteja atalhos de letra válidos para toda a página contra contextos de digitação e repetições indesejadas.
  • Use input para reagir a texto editado, incluindo colagem.
  • focusin e focusout borbulham; focus e blur não.
  • relatedTarget informa o outro destino ou origem do foco.

3.2 Ativação e movimento do ponteiro

Uma pessoa pode usar mouse, dedo, caneta ou teclado. Escolha um evento conforme a interação necessária. click expressa ativação; eventos de ponteiro descrevem pressionamento, movimento e liberação.

Mantenha ações disponíveis pelo teclado

Um botão nativo emite click quando ativado com Enter ou a barra de espaço. Um link com foco faz isso com Enter. Associar uma ação apenas a pointerdown ou mousedown deixa de captar essas ativações pelo teclado. Use click para ações como abrir um painel; use pointerdown quando o trabalho precisar começar no pressionamento, como em um arraste.

Um clique com ponteiro ocorre após pressionar e soltar. Quando essas ações ocorrem em elementos diferentes, o clique pode ter como alvo o ancestral comum mais próximo. dblclick ocorre após dois cliques rápidos; event.detail conta cliques rápidos sucessivos. auxclick trata cliques não primários. contextmenu pode vir de um clique secundário, de um toque longo ou de um comando de menu do teclado.

Use uma única família de eventos de ponteiro

pointerdown, pointermove, pointerup e pointercancel abrangem mouse, toque e caneta. pointerType identifica o dispositivo como "mouse", "touch" ou "pen"; pointerId distingue ponteiros ativos, incluindo dois dedos.

Famílias mais antigas de eventos de mouse e toque ainda existem. Os navegadores podem emitir eventos de mouse para compatibilidade após eventos de ponteiro. Registrar tanto pointerdown quanto mousedown para a mesma ação pode, portanto, executá-la duas vezes.

Escolha coordenadas adequadas à tarefa
CoordenadasOrigem
clientX, clientYCanto superior esquerdo da área de visualização visível
pageX, pageYCanto superior esquerdo do documento, incluindo a rolagem
offsetX, offsetYBorda do preenchimento do elemento alvo

Quando o documento é rolado 300 px para baixo e um clique ocorre 100 px abaixo do topo da área de visualização, clientY é 100 e pageY é 400. Mantenha ambas as posições no mesmo referencial de coordenadas ao calcular o movimento. Uma mudança no alvo aninhado também pode mudar a origem das coordenadas de deslocamento.

button informa qual botão mudou em um evento de pressionamento ou liberação: 0 primário, 1 meio, 2 secundário. buttons informa a combinação atualmente pressionada: o primário contribui com 1, o secundário com 2 e o do meio com 4. Assim, buttons === 3 significa que o primário e o secundário estão pressionados; não significa que o botão do meio mudou.

Escolha o comportamento de passagem para um controle inteiro

Eventos over/out borbulham e podem disparar quando o ponteiro cruza os limites dos filhos. Eventos enter/leave não borbulham e descrevem a entrada ou saída do elemento inteiro, incluindo seus filhos. Uma dica pode evitar a oscilação nos limites dos filhos com pointerenter e pointerleave.

Usuários de toque e teclado não passam o ponteiro. Ofereça informações essenciais também por clique ou foco. Para um efeito visual de passagem sem comportamento adicional, o CSS :hover é mais simples que um ouvinte.

Principais conclusões

  • Use click para ativação, incluindo a ativação nativa pelo teclado.
  • Eventos de ponteiro abrangem mouse, toque e caneta em uma única família.
  • Escolha coordenadas do mesmo referencial para os cálculos.
  • button identifica uma mudança; buttons informa a combinação pressionada.
  • Enter/leave tratam um elemento e seus filhos como um todo.
  • Informações essenciais precisam estar acessíveis por outros meios além da passagem do ponteiro.

3.3 Um arraste que continua acompanhando o ponteiro

O arraste precisa manter informações entre vários eventos. Armazene as coordenadas iniciais do ponteiro e a posição inicial do elemento. Cada movimento aplica a diferença em relação a esse ponto inicial, para que o elemento não salte colocando seu canto sob o ponteiro.

Calcule o deslocamento

Uma caixa começa em left: 100px; top: 50px. O ponteiro começa nas coordenadas 220, 140 da área de visualização e se move para 260, 125. A mudança horizontal é 40 px; a mudança vertical é −15 px. Somar essas mudanças à posição inicial da caixa resulta em left: 140px; top: 35px.

Use coordenadas de cliente consistentes para as duas leituras do ponteiro. O cálculo geral é a posição inicial do elemento mais o deslocamento do ponteiro. Não some cada deslocamento completo à posição já atualizada da caixa, pois isso contaria novamente o movimento anterior.

Armazene e capture um ponteiro

Para uma caixa sem margem e com posicionamento absoluto dentro de um contêiner com posicionamento relativo:

let start = null;
box.addEventListener("pointerdown", (event) => {
  if (start || event.button !== 0) return;
  start = { id: event.pointerId, x: event.clientX,
    y: event.clientY, left: box.offsetLeft,
    top: box.offsetTop };
  box.setPointerCapture(event.pointerId);
});
box.addEventListener("pointermove", (event) => {
  if (!start || event.pointerId !== start.id) return;
  box.style.left = start.left +
    (event.clientX - start.x) + "px";
  box.style.top = start.top +
    (event.clientY - start.y) + "px";
});
function endDrag(event) {
  if (start && event.pointerId === start.id) start = null;
}
box.addEventListener("pointerup", endDrag);
box.addEventListener("pointercancel", endDrag);

O ID armazenado descarta movimentos e liberações de um segundo ponteiro. offsetLeft e offsetTop fornecem posições iniciais como números; os estilos precisam do sufixo "px".

A captura de ponteiro mantém os eventos seguintes desse ponteiro direcionados à caixa mesmo quando ele se move para fora dela. O navegador libera a captura após a liberação ou o cancelamento do ponteiro. releasePointerCapture(id) pode liberá-la antes.

Trate a tomada de controle pelo navegador

Um gesto de toque pode se tornar rolagem ou zoom da página, causando pointercancel. Encerre o arraste nesse caso e também em pointerup; caso contrário, um estado desatualizado pode continuar movendo a caixa depois. Aplique touch-action: none à superfície de arraste antes da interação para reservar o gesto. Mantenha essa regra local para que o restante da página possa rolar.

Use user-select: none na superfície arrastável para evitar a seleção de texto. Defina draggable="false" em suas imagens para impedir o comportamento nativo de arraste de imagem.

Ofereça outra forma de mover

Ofereça movimento pelo teclado para um controle com foco e botões de movimento que possam ser clicados ou tocados. Teclas de seta, por si só, não fornecem uma alternativa ao arraste com um único ponteiro. O critério de sucesso 2.5.7 das WCAG 2.2 exige essa alternativa, a menos que o arraste seja essencial ou seja um comportamento não modificado do navegador. Botões nativos de movimento podem servir tanto a usuários de teclado quanto de ponteiro.

A API HTML Drag and Drop, separada desse padrão, usa dragstart, dragover e drop para transferir dados, como arquivos. Sua sequência de eventos difere desta mudança de posição baseada em ponteiro.

Principais conclusões

  • Calcule cada posição a partir do início armazenado mais o deslocamento do ponteiro.
  • Capture e acompanhe o ID do ponteiro ativo.
  • Encerre o arraste tanto em pointerup quanto em pointercancel.
  • Aplique regras de toque e seleção à superfície de arraste.
  • Ofereça acesso pelo teclado e uma alternativa que possa ser clicada ou tocada.
4

Tratar formulários e validar as entradas antes do envio

Formulários combinam vários tipos de estado: texto, valores numéricos, escolhas marcadas e nomes repetidos. Leia esses valores no evento adequado e depois trate o envio do formulário como uma única ação. Restrições HTML fornecem regras de validação comuns, enquanto JavaScript acrescenta relações entre campos e feedback mais claro. Um formulário útil preserva o trabalho do usuário, explica cada correção e coloca o foco onde a próxima edição deve ocorrer.

4.1 Ler valores quando eles mudam

Controles de formulário expõem diferentes tipos de estado. O value de um campo de texto é uma cadeia de caracteres; o checked de uma caixa de seleção é um booleano. Ler a propriedade correta é o primeiro passo para cálculos e prévias confiáveis.

Converta números de forma deliberada

Mesmo <input type="number"> tem um value que é uma cadeia de caracteres. Com o texto "3", somar 1 resulta em "31". Number(input.value) + 1 resulta em 4. Uma entrada numérica também expõe valueAsNumber.

Uma entrada vazia precisa de uma decisão própria. Number("") resulta em 0, o que pode fazer uma quantidade ausente parecer um zero real. Verifique primeiro input.value === "" ou use valueAsNumber, que resulta em NaN para um campo numérico vazio. Teste esse resultado com Number.isNaN().

Leia o estado selecionado
ControlePropriedade a ler
Texto, textarea, lista de seleçãovalue
Entrada numérica usada em cálculosvalueAsNumber ou conversão de um value não vazio
Caixa de seleçãochecked para o estado ligado/desligado
Grupo de botões de opção chamado sizeform.elements.size.value para o valor selecionado

O value de uma caixa de seleção é seu texto de envio configurado ou "on" se nenhum for fornecido. Ele não informa se ela está marcada. Uma lista de seleção informa o valor da opção escolhida. Para encontrar o próprio elemento de opção selecionado, consulte input[name="size"]:checked.

Associe o evento à atualização

input informa edições do usuário à medida que ocorrem, incluindo digitação e colagem. change informa uma escolha confirmada: depois que um campo de texto alterado perde o foco ou imediatamente quando uma caixa de seleção, um botão de opção ou uma lista de seleção é alterado.

message.addEventListener("input", () => {
  counter.textContent = 280 - message.value.length +
    " characters left";
});

Após “Hello”, cinco caracteres foram usados e o contador mostra “275 characters left”. Um ouvinte de keydown seria executado antes de o novo caractere entrar no valor e não detectaria uma colagem por menu. Atribuir message.value por código não dispara input nem change; chame também a função de atualização diretamente.

Colete os campos nomeados de um formulário

form.elements.email.value acessa um controle pelo nome ou ID. Use form.elements["first-name"] para um nome com hífen. O envio usa nomes: um ID sozinho não coloca um campo nos dados.

const data = new FormData(form);
const email = data.get("email");
const topics = data.getAll("topics");

FormData coleta os pares de nome e valor atuais que podem ser incluídos. Caixas de seleção não marcadas, controles desabilitados e campos sem nome são omitidos. get() retorna o primeiro valor de um nome; getAll() preserva valores repetidos, como vários tópicos marcados. Controles de arquivo podem fornecer objetos de arquivo; controles de texto comuns fornecem cadeias de caracteres.

Object.fromEntries(data) é conveniente para nomes distintos, mas mantém apenas o último par para nomes repetidos. Escolha getAll() quando cada seleção importar. Como input borbulha, um ouvinte no formulário pode ler event.target para atualizar qualquer campo alterado.

Principais conclusões

  • Converta a cadeia de caracteres de um campo antes de calcular e trate um número vazio separadamente.
  • Leia o estado de uma caixa de seleção em checked.
  • Use input para edições em tempo real e change para escolhas confirmadas.
  • FormData inclui controles nomeados que podem ser coletados, não todos os controles.
  • getAll() preserva nomes repetidos; a conversão para objeto não.
  • A atribuição de valor por código não emite eventos de edição.

4.2 Tratar o envio do formulário

O envio pertence ao formulário. Ouça seu evento submit para tratar por um único caminho um clique em botão de envio, Enter em um campo de uma linha e uma chamada a requestSubmit() por script.

Substitua a navegação por uma atualização da página

Normalmente, um formulário envia dados para sua URL action e carrega a resposta. Sem uma ação, o destino é a página atual. O método padrão GET coloca os dados na URL. Para atualizar a página atual com JavaScript, cancele essa ação padrão:

const form = document.querySelector("#new-todo");
form.addEventListener("submit", (event) => {
  event.preventDefault();
  const data = new FormData(form);
  const title = data.get("title").trim();
  if (title === "") return;
  addTodo(title);
  form.reset();
});

Esse formulário tem um campo de texto habilitado chamado title. O ouvinte remove espaços das extremidades, ignora um resultado vazio, adiciona um item e redefine os campos para seus valores iniciais. reset() nem sempre significa vazio; um controle com valor inicial retorna a esse valor.

Se o item aparecer brevemente e desaparecer quando a página recarregar, verifique se preventDefault() está faltando. Um ouvinte de clique no botão, por si só, não é o ponto adequado para tratar o formulário, especialmente quando outro caminho o envia.

Saiba o que aciona o envio

O envio implícito por Enter pode clicar no botão de envio padrão habilitado. Enter em um textarea insere uma nova linha. Um botão dentro de um formulário é, por padrão, um botão de envio quando seu tipo é omitido, então um botão “Mostrar senha” deve usar explicitamente type="button".

Quando há vários botões de envio, event.submitter identifica o que foi usado. Ele pode ser null em caminhos sem um botão específico, então o código deve verificar antes de lê-lo:

const button = event.submitter;
const intent = button ? button.value : "save";
const data = button ? new FormData(form, button) :
  new FormData(form);

Um botão responsável pelo envio com nome, como name="intent" value="publish", acrescenta esse par quando passado a FormData. Uma chamada a FormData(form) por si só não inclui o par de nome e valor de um botão de envio.

Preserve o caminho de validação
Caminho de envioValidação automáticaOuvinte de submit
Ativação de envio ou requestSubmit()Executada, a menos que seja ignorada por atributos de validaçãoExecutado se a validação permitir
form.submit()IgnoradaIgnorado

A validação nativa é executada antes do evento de envio. Se um campo obrigatório vazio falhar, o navegador informa o problema e não dispara submit. Uma verificação personalizada apenas dentro desse ouvinte não será executada nessa tentativa malsucedida. novalidate no formulário desativa a etapa de validação automática.

Use requestSubmit() quando o código precisar do caminho normal de validação e evento de envio. Ele solicita o envio sem disparar um clique no botão. Passe um botão de envio específico a requestSubmit(button) quando as configurações de envio desse botão devam ser aplicadas.

Principais conclusões

  • Trate submit no formulário, abrangendo envios pelo usuário e por script.
  • Cancele o envio padrão quando JavaScript substituir a navegação.
  • Dê type="button" a botões de formulário que não enviam.
  • Use submitter para distinguir botões de envio e incluir seus dados quando necessário.
  • A validação precede submit; requestSubmit() preserva esse caminho.
  • submit() ignora a validação e o evento de envio.
  • reset() restaura os valores iniciais.

4.3 Deixar o HTML descrever regras de validação

O HTML pode descrever muitas regras de entrada sem um teste personalizado em JavaScript. O navegador verifica essas regras durante o envio e expõe os resultados para seu código. Comece pelas restrições que correspondem aos dados de que você precisa.

Escolha uma restrição
AtributoRegra
requiredUm valor ou uma seleção obrigatória deve ser fornecido.
type="email" ou "url"O valor deve ter a sintaxe esperada.
min, max, stepValores numéricos ou de data devem respeitar limites e incrementos.
minlength, maxlengthO texto inserido pelo usuário deve cumprir uma regra de comprimento.
patternUm valor de texto não vazio deve corresponder a uma expressão para o valor inteiro.

Para pattern="[0-9]{5}", “12345” passa; “1234”, “123456” e “12345a” falham. O padrão abrange o valor inteiro, não qualquer parte correspondente. Uma entrada vazia ignora a verificação de padrão, então adicione required quando a omissão não for permitida.

A validação de e-mail verifica a sintaxe, não se uma caixa de entrada existe. Tanto “ann@example.com” quanto “ann@example” passam na regra de e-mail do navegador, enquanto “ann.example.com” não passa. Um padrão adicional pode impor um formato mais específico quando a aplicação exigir.

Leia o motivo da falha

O objeto validity de um campo contém indicadores booleanos. valueMissing, typeMismatch, patternMismatch, tooShort e tooLong descrevem texto ausente ou malformado. rangeUnderflow, rangeOverflow e stepMismatch descrevem restrições numéricas. badInput abrange uma entrada que o navegador não consegue transformar em um valor utilizável, e customError registra uma mensagem de validade personalizada. valid é verdadeiro quando nenhuma restrição falha.

Para um campo numérico com min="0" max="10" step="2", 12 está acima do máximo, 7 não segue o incremento permitido e 6 passa. Mais de um indicador pode ser verdadeiro; não suponha que todo campo inválido tenha exatamente um problema.

Verifique silenciosamente ou informe de forma visível

checkValidity() retorna um booleano e dispara invalid nos controles que falham sem mostrar a mensagem do navegador. reportValidity() verifica e também informa o problema ao usuário. Chame qualquer um deles em um campo ou formulário. validationMessage fornece a mensagem no idioma do navegador. O evento invalid não borbulha.

Restrições de comprimento de texto se aplicam ao texto inserido pelo usuário. Atribuir input.value = "ab" no código não torna tooShort verdadeiro apenas porque minlength é 3. maxlength normalmente também impede que o usuário continue digitando além do limite.

Mostre erros em um momento útil

:invalid se aplica imediatamente, então um campo obrigatório ainda não tocado já corresponde ao seletor. :user-invalid espera uma interação do usuário ou uma tentativa de envio e pode evitar um campo vermelho cedo demais. Use texto para explicar o erro, além de um estilo visual.

novalidate ignora a validação automática de envio para o formulário; formnovalidate a ignora para um botão de envio. Eles não removem restrições nem desativam checkValidity(). As verificações do navegador ajudam os usuários a corrigir erros; o servidor deve validar novamente os dados recebidos, pois uma requisição pode contornar a página.

Principais conclusões

  • Use restrições HTML para valores obrigatórios, sintaxe, intervalos, incrementos, comprimento e padrões.
  • Um padrão corresponde ao valor não vazio inteiro; use required para rejeitar uma entrada vazia.
  • Leia os indicadores de validity para identificar por que um campo falhou.
  • checkValidity() verifica; reportValidity() também mostra o resultado.
  • Atributos que ignoram a validação mantêm a API de validade utilizável.
  • Valide também os dados recebidos no servidor.

4.4 Regras personalizadas e mensagens de erro úteis

Uma regra que envolve dois campos precisa de código. Por exemplo, uma confirmação deve corresponder a uma senha, ou uma data final deve vir após uma data inicial. Mantenha a regra separada de como e quando seu erro é exibido.

Defina e limpe um erro personalizado

Uma cadeia de caracteres não vazia passada a setCustomValidity() marca o campo como inválido e define customError. Passar "" limpa essa falha personalizada; restrições de obrigatoriedade, padrão ou outras ainda podem falhar.

function checkMatch() {
  const matches = confirm.value === password.value;
  confirm.setCustomValidity(matches ? "" :
    "The passwords do not match.");
}
password.addEventListener("input", checkMatch);
confirm.addEventListener("input", checkMatch);

Verifique novamente ambas as dependências. Alterar a primeira senha pode invalidar uma confirmação que antes estava correta. Uma mensagem que nunca é limpa mantém o campo inválido depois que a pessoa corrige a divergência. Execute também a verificação inicial quando os campos puderem começar com valores.

Entradas de data fornecem cadeias ISO como "2026-03-10", independentemente do formato local de data exibido. Valores não vazios desses controles podem ser comparados como texto. Se a regra disser que o fim deve ser posterior ao início, rejeite end.value <= start.value, incluindo a igualdade. Trate datas ausentes com required ou com uma verificação separada de valor vazio.

Explique a próxima ação útil

Uma mensagem deve identificar o problema e sua correção. Para um e-mail ausente, diga “Digite seu endereço de e-mail.” Para um texto de e-mail malformado, diga “Digite um endereço de e-mail no formato nome@example.com.” Mantenha o valor inserido para que a pessoa possa editá-lo.

Um campo de nome obrigatório aceita espaços porque eles formam uma cadeia não vazia. Verifique name.value.trim() === "" quando espaços em branco nas extremidades não devem contar. Limpe esse erro personalizado quando aparecer um texto com conteúdo.

Associe mensagens aos controles
<label for="email">Email</label>
<input id="email" name="email" type="email"
  required aria-describedby="email-error">
<p id="email-error"></p>

Coloque o erro nesse parágrafo e defina aria-invalid="true" enquanto o campo tiver um erro. Limpe o texto e remova aria-invalid ou defina-o como "false" após a correção. aria-describedby associa a explicação ao campo para a tecnologia assistiva. Use texto; uma borda vermelha sozinha não informa a todos o que falhou.

Escolha o fluxo de validação

Para mensagens inteiramente personalizadas, adicione novalidate e use um ouvinte de submit no formulário. Atualize as regras personalizadas, inspecione a validade dos campos, escreva suas mensagens e impeça o envio quando algum falhar. Mova o foco para o primeiro campo inválido ou para um resumo de erros com links. Se o JavaScript também tratar localmente o envio bem-sucedido, cancele esse envio padrão.

Evite informar que um texto de e-mail está incompleto a cada tecla pressionada no início. Uma sequência útil é mostrar erros após a perda de foco ou o envio e depois verificar novamente um erro já informado em input.

Principais conclusões

  • Mensagens personalizadas não vazias tornam um campo inválido; "" limpa apenas esse erro personalizado.
  • Verifique novamente cada campo do qual uma regra entre campos depende.
  • Para uma ordem estrita de datas, rejeite tanto a igualdade quanto um fim anterior.
  • Explique uma correção em texto e associe-a ao campo.
  • Limpe os erros visíveis e o estado de erro ARIA após a correção.
  • O feedback personalizado no envio precisa de um fluxo explícito de validade e foco.
5

Construir controles personalizados que todos possam usar

Escolher um elemento nativo fornece grande parte do comportamento de um controle antes de qualquer ouvinte ser escrito. Controles personalizados precisam do mesmo cuidado: um nome claro, acesso pelo teclado, foco visível e estado que corresponda ao que a tecnologia assistiva informa. Grupos precisam de movimento previsível entre itens. Quando o conteúdo abre, fecha ou desaparece, um destino de foco escolhido intencionalmente permite que o usuário continue a interação sem procurar novamente pela página.

5.1 Começar com um controle nativo

Um controle precisa de mais do que uma resposta a clique. As pessoas precisam ser capazes de encontrá-lo, alcançá-lo, entender sua finalidade, operá-lo e ver onde está o foco. O HTML nativo já fornece grande parte desse comportamento.

Escolha o elemento para a tarefa

Use um <button> para uma ação, um <a href> para navegação e um controle de formulário com rótulo para entrada. <details> com <summary> fornece um controle de expansão e recolhimento. Estilize esses elementos com CSS para combinar com a página. Um botão com foco é ativado por Enter ou pela barra de espaço sem um ouvinte de teclado adicional.

Um div com ouvinte de clique não tem a semântica nem o comportamento de teclado nativos do botão. Atribuir-lhe role="button" altera o que a tecnologia assistiva anuncia, mas não permite que ele receba foco nem transforma pressionamentos de teclas em cliques.

NecessidadeBotão nativoDiv personalizado como botão
PapelIntegradoAdicione role="button".
Foco pelo tecladoIntegradoAdicione tabindex="0".
Enter e barra de espaçoIntegradosAdicione tratamento de teclado.
Nome acessívelGeralmente seu textoForneça texto significativo ou um nome ARIA.
Comportamento desabilitadodisabledVerifique aria-disabled no código.
Mantenha a ordem de foco previsível

tabindex="0" adiciona um elemento à sequência normal de Tab na ordem do documento. tabindex="-1" permite foco por código sem adicionar uma parada de Tab. Valores positivos movem elementos para antes da sequência usual e são difíceis de manter; evite-os.

Nenhuma das duas configurações acrescenta comportamento de ativação. Um botão personalizado que pode receber foco ainda precisa de um ouvinte para sua operação pelo teclado. Um papel, uma parada de Tab e uma função de retorno resolvem partes diferentes da interação.

Dê um nome a cada controle

Um leitor de tela usa um nome acessível para distinguir controles. Um botão de texto pode usar seu texto visível. Um campo de texto ou uma lista de seleção precisa de um rótulo associado, como <label for="email">Email</label> combinado com id="email". aria-labelledby pode fazer referência a um texto visível em outro lugar; aria-label pode fornecer um nome quando não houver texto visível adequado.

Um botão de fechar que contém apenas um ícone pode ser <button type="button" aria-label="Close">×</button>. O nome descreve a ação em vez de fazer o usuário deduzir o significado do símbolo.

Mostre e faça cumprir o estado

Mantenha um indicador de foco visível. Se substituir o contorno padrão, forneça um substituto claro com :focus-visible, por exemplo outline: 3px solid #1a73e8. Removê-lo sem substituição oculta a posição do usuário de teclado.

Um botão nativo desabilitado sai da sequência de Tab e não pode ser ativado normalmente. aria-disabled="true" apenas comunica a indisponibilidade. A ação de clique e de teclado de um controle personalizado deve verificar esse estado e retornar sem agir. Centralizar essa verificação na função de ativação mantém os dois caminhos de entrada consistentes.

Principais conclusões

  • Use um elemento nativo que corresponda à ação ou entrada.
  • Um papel ARIA fornece semântica, não comportamento.
  • Use tabindex="0" para acesso normal por Tab e -1 para foco apenas por código.
  • Forneça um nome acessível e um indicador de foco visível.
  • Faça cumprir aria-disabled no código de ativação.

5.2 Manter o comportamento do teclado e o estado juntos

Um controle personalizado deve produzir o mesmo resultado independentemente de como é ativado. Mantenha a ação em uma função, encaminhe a ela o uso de teclado e ponteiro e atualize o estado lido pela estilização e pela tecnologia assistiva.

Dê ativação por teclado a um botão personalizado
fakeButton.addEventListener("click", activate);
fakeButton.addEventListener("keydown", (event) => {
  if (event.key === "Enter" || event.key === " ") {
    event.preventDefault();
    activate();
  }
});

Isso se aplica a um botão personalizado que pode receber foco. Cancelar a barra de espaço impede a rolagem da página durante a ação. Um botão nativo já produz cliques pela ativação com teclado, então adicionar um segundo caminho por tecla pode executar a ação duas vezes.

Escolha o estado correspondente ao controle
ControleEstado
Botão de alternância com rótulo fixoaria-pressed="true" ou "false"
Botão que abre um controle de expansão e recolhimentoaria-expanded="true" ou "false"
Caixa de seleção ou interruptor personalizadoaria-checked="true" ou "false"

Um botão de alternância “Silenciar” mantém esse rótulo e altera aria-pressed. Se o design mudar o rótulo da ação para “Ativar som”, omita aria-pressed. Uma caixa de seleção usa role="checkbox" e a barra de espaço para alternar; um interruptor usa role="switch" para o estado ligado/desligado.

Atributos contêm cadeias de caracteres. Compare getAttribute("aria-expanded") com "true", não com o booleano true:

detailsButton.addEventListener("click", () => {
  const open = detailsButton.getAttribute(
    "aria-expanded") === "true";
  detailsButton.setAttribute("aria-expanded", String(!open));
  panel.hidden = open;
});

Quando open era verdadeiro, o novo estado é falso e o painel fica oculto. aria-controls pode identificar o painel pelo ID. Os elementos nativos <details> e <summary> fornecem o comportamento de expansão e recolhimento sem esse script.

Use o atributo de estado como fonte para a estilização, como [aria-pressed="true"], para que os estados visível e anunciado mudem juntos. Feche pop-ups com Escape e devolva o foco ao controle de abertura.

Dê ao grupo uma única parada de Tab

Abas, barras de ferramentas e grupos de botões de opção usam Tab para entrar ou sair do grupo e teclas de seta para se mover dentro dele. O tabindex itinerante mantém o item atual em 0 e os outros em -1. Ao mover, defina o item anterior como -1, o novo como 0 e dê foco ao novo item.

Para três itens, mover à direita a partir do índice 2 retorna a 0 com (2 + 1) % 3. Mover à esquerda a partir de 0 usa (0 - 1 + 3) % 3 para chegar a 2. Some o tamanho antes da operação de resto porque -1 % 3 em JavaScript é −1.

Verifique com o teclado: entre no controle, veja o foco, ative-o com as teclas adequadas, mova-se dentro de um grupo e feche um pop-up com Escape. Verifique o estado visível e o estado ARIA a cada mudança.

Principais conclusões

  • Encaminhe clique, Enter e barra de espaço de um botão personalizado para uma única ação.
  • Botões nativos já oferecem ativação por clique pelo teclado.
  • Escolha aria-pressed, aria-expanded ou aria-checked conforme o estado correspondente.
  • Compare valores ARIA como cadeias de caracteres e atualize a estilização a partir do mesmo estado.
  • O tabindex itinerante dá a um grupo uma parada de Tab e movimento por teclas de seta.
  • Escape fecha um pop-up e devolve o foco ao controle de abertura.

5.3 Mover o foco quando a página mudar

O foco determina para onde vai a próxima ação do teclado. Se o controle com foco desaparecer, o usuário pode perder sua posição. Trate o foco como parte da atualização da página, especialmente ao abrir uma caixa de diálogo, excluir um item ou informar um erro.

Abra uma caixa de diálogo e retorne ao controle de abertura

Lembre qual elemento tinha foco antes de abrir. Mova o foco para a nova interação e restaure-o ao fechar:

let opener;
openButton.addEventListener("click", () => {
  opener = document.activeElement;
  dialog.showModal();
});
dialog.addEventListener("close", () => {
  if (opener && opener.isConnected) opener.focus();
});

showModal() em uma caixa de diálogo nativa move o foco para dentro dela e torna o restante da página inerte, de modo que não possa ser clicado nem receber foco enquanto a caixa modal estiver aberta. Escape normalmente causa um evento cancel, seguido pelo fechamento e por um evento close. Um ouvinte de cancel pode impedir o fechamento se a aplicação precisar desse comportamento.

Escolha um local inicial de foco útil na caixa de diálogo, como seu primeiro controle relevante. Para um pop-up personalizado, o código deve mover o foco intencionalmente. Quando o controle de abertura original não existir mais, escolha um controle útil próximo em vez de tentar dar foco a um elemento desconectado.

Permita que um destino útil receba foco

Um título ou resumo de erros normalmente não pode receber foco. Dê a ele tabindex="-1" antes de chamar .focus(). Ele poderá receber o foco intencionalmente sem se tornar uma parada extra durante a navegação normal por Tab. Use 0 apenas quando ele pertencer a essa sequência normal.

Preserve a posição após uma exclusão

Antes de remover um item de lista cujo botão de exclusão tem foco, encontre o próximo destino útil. Dê foco ao botão do próximo item; se não houver próximo item, use o botão do item anterior. Se a lista ficar vazia, dê foco ao seu título com tabindex="-1".

Encontrar o destino antes da remoção evita perder a relação com os itens vizinhos. Não envie o foco para o início do documento após cada exclusão; a pessoa deve poder continuar trabalhando perto da alteração.

Mantenha o foco em uma interação em andamento

Um pop-up pode fechar quando o foco sai de toda a sua área. O evento focusout, que borbulha, fornece o destino:

menu.addEventListener("focusout", (event) => {
  if (!menu.contains(event.relatedTarget)) {
    menu.hidden = true;
  }
});

Mover-se entre dois controles do menu não o fecha porque o destino permanece dentro dele. Um destino null também está fora; contains(null) é falso. Não devolva o foco automaticamente ao controle de abertura quando o usuário tiver se movido intencionalmente para outro controle da página.

Torne as mudanças previsíveis

Após uma validação personalizada de formulário malsucedida, dê foco ao primeiro campo inválido ou a um resumo de erros com links para eles. A validação nativa já dá foco a um campo que falha. Mantenha o texto de erro disponível para que a pessoa saiba o que corrigir.

Não pule para um novo campo enquanto o usuário estiver digitando nem navegue assim que uma lista de seleção mudar. Permita que uma ação clara confirme a alteração. O movimento de foco deve apoiar uma ação deliberada ou a recuperação, não interromper a entrada normal.

Principais conclusões

  • Lembre o controle de abertura e restaure o foco em um destino disponível quando uma caixa de diálogo fechar.
  • Use tabindex="-1" para um título ou resumo que recebe foco por código.
  • Após uma exclusão, dê foco a um item vizinho ou ao título da lista vazia.
  • Use relatedTarget para distinguir movimentos internos de foco da saída de um pop-up.
  • Dê foco a um destino de erro após uma validação malsucedida; evite saltos inesperados de foco.

Exercícios resolvidos de Eventos e páginas interativas

5 Lições Interativas

1

Construir e inspecionar ouvintes de eventos

13 passos
Registre um contador, inspecione cliques aninhados e corrija a duração dos ouvintes.
  1. 1
    IntroduçãoFazer um botão responder

    Um ouvinte conecta um evento a uma função. Construa um pequeno contador escolhendo o botão, registrando sua ação e mantendo o total entre chamadas. Depois, inspecione um click aninhado e controle a duração do ouvinte.

    Observe a diferença entre o código de configuração, que é executado agora, e a função de retorno, que o navegador chama quando o evento escolhido acontece.

  2. 2
    ExemploArmazenar o total fora da função de retorno

    Selecione o botão existente e armazene sua contagem antes do registro:

    const button = document.querySelector("#like");
    let likes = 0;
    button.addEventListener("click", () => {
      likes = likes + 1;
      button.textContent = "Likes: " + likes;
    });
    

    Cada chamada soma ao total anterior. Após três cliques, o rótulo é “Likes: 3”. Uma contagem declarada dentro da função de retorno recomeçaria a cada chamada.

  3. 3
    DicaPassar a ação sem chamá-la

    addEventListener("click", showMenu) passa uma função para uso posterior. showMenu() a chamaria durante a configuração. Quando argumentos forem necessários, use () => showMenu("main").

    Carregue o script depois que o botão existir, por exemplo com defer, e mantenha a grafia exata do evento. Um ouvinte de "Click" não recebe eventos "click" comuns.

  4. 4
    DesafioCorrigir um registro

    Um botão deve abrir o painel de dicas a cada ativação. Atualmente, a configuração usa button.addEventListener("click", openTips()). O que deve mudar e por quê?

    ---reveal---

    Passe openTips sem parênteses. Isso fornece a função de retorno para ser executada em um click posterior. Chamar openTips() durante a configuração abre o painel imediatamente e passa seu resultado em vez de preservar a ação para o evento.

  5. 5
    ExplicaçãoLer as duas propriedades de elemento

    Para um botão que contém uma imagem, clicar na imagem faz dela o target. No ouvinte do botão, currentTarget é o botão.

    O target informa onde o evento começou; o target atual informa onde essa função de retorno foi registrada. Essa diferença explica por que ler o dataset de um botão a partir de target pode falhar quando o click atinge sua imagem.

  6. 6
    ExemploLer os dados do botão que os possui

    Suponha que button tenha data-id="7" e contenha um ícone:

    button.addEventListener("click", (event) => {
      console.log(event.currentTarget.dataset.id);
    });
    

    O resultado é "7" tanto para um click no ícone quanto para um click no fundo do botão. A mesma expressão funciona em um ouvinte definido com função de seta ou função comum. O this de uma função de seta não identifica automaticamente o botão.

  7. 7
    DesafioIdentificar o elemento do ouvinte

    Uma seção contém um botão com um span. Um ouvinte de click está registrado apenas na seção, e o span é clicado. O que target e currentTarget identificam durante essa função de retorno?

    ---reveal---

    target identifica o span onde o evento começou. currentTarget identifica a seção onde o ouvinte foi registrado. A origem do evento não é substituída pelo ancestral que o recebe.

  8. 8
    ExplicaçãoManter a referência para remoção

    A remoção precisa do mesmo tipo de evento, objeto de função de retorno e configuração de captura:

    const handler = () => closePanel();
    button.addEventListener("click", handler);
    button.removeEventListener("click", handler);
    

    Uma função anônima pode ser removida quando salva dessa forma. Escrever uma nova () => closePanel() na chamada de remoção cria outro objeto e não corresponde ao registro anterior.

  9. 9
    ConexãoEncerrar vários registros juntos

    Um recurso temporário pode passar um sinal de AbortController a vários registros. Chamar controller.abort() remove esses ouvintes, incluindo funções de retorno salvas ou anônimas.

    Use um novo controlador para outro período de uso. Para uma única resposta, { once: true } remove esse registro após sua execução. Nenhuma das duas opções impede que funções de retorno distintas se acumulem antes do fim de sua duração.

  10. 10
    DesafioDiagnosticar configurações repetidas

    Abrir um painel registra um novo ouvinte anônimo de teclado no documento a cada vez. Fechar oculta o painel, mas deixa o ouvinte. Após três aberturas, uma tecla aciona três ações. Como corrigir o ciclo de vida?

    ---reveal---

    Remova os registros quando o painel fechar, por exemplo, cancelando seu sinal compartilhado, e crie um novo controlador ao reabri-lo. Como alternativa, salve uma função de retorno e remova essa mesma referência. Ocultar o painel não remove um ouvinte do documento.

  11. 11
    Ideia-chaveDisparar uma notificação imediatamente

    Para notificar outro código, crie um CustomEvent com seus dados em detail. Defina bubbles: true se os ancestrais devam recebê-lo:

    item.dispatchEvent(new CustomEvent("cart:add", {
      detail: { id: 42 }, bubbles: true
    }));
    

    Os ouvintes são executados antes de a chamada retornar. O evento disparado tem isTrusted falso. É uma notificação enviada pelo seu código, não uma solicitação para que o navegador espere por uma ação do usuário.

  12. 12
    DesafioCombinar origem e duração

    Um tratador de click de um botão usa seu próprio data-key e deve agir apenas na primeira ativação. Ele contém um ícone SVG. Qual propriedade e qual opção atendem aos dois requisitos?

    ---reveal---

    Leia event.currentTarget.dataset.key no ouvinte direto do botão e registre-o com { once: true }. A propriedade identifica o botão que possui os dados mesmo em um click no ícone. A opção remove esse registro após sua primeira chamada.

  13. 13
    RecapitulaçãoVerificar um ouvinte em três pontos

    Quando uma interação falhar, inspecione a configuração, os dados da função de retorno e sua duração. Confirme que o elemento existe e que o nome do evento é exato; inspecione target e currentTarget durante a chamada; depois procure remoções ausentes ou registros repetidos. Essas verificações distinguem um ouvinte que nunca recebe um evento de um que o recebe corretamente, mas age sobre o elemento errado.

2

Rastrear eventos e delegar ações

13 passos
Preveja a ordem dos ouvintes, substitua ações padrão do navegador e trate novos itens de lista.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoRastrear um clique por um cartão
  2. 2
    ExemploLer o caminho de subida
  3. 3
    ExplicaçãoAdicionar o caminho de descida
  4. 4
    DesafioRastrear uma árvore menor
  5. 5
    ExplicaçãoSubstituir a navegação
  6. 6
    Ideia-chaveInterromper o percurso é uma escolha diferente
  7. 7
    DesafioManter ativo um observador no pai
  8. 8
    ExplicaçãoMover o ouvinte para a lista
  9. 9
    ExemploEncontrar e verificar o botão de remoção
  10. 10
    DesafioTratar um ícone aninhado
  11. 11
    DicaUsar um evento que alcance o contêiner
  12. 12
    DesafioManter a abertura e o fechamento separados
  13. 13
    RecapitulaçãoEscolher um limite para cada ação
3

Tratar teclas e construir um arraste com ponteiro

16 passos
Escolha eventos de entrada, trabalhe com coordenadas e torne um arraste robusto e utilizável.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoEscolher o nível correto de entrada
  2. 2
    ExplicaçãoSeparar significado de posição
  3. 3
    DicaProteger a digitação e tratar repetições
  4. 4
    DesafioEscolher um evento para uma prévia
  5. 5
    ConexãoPermitir ativação pelo teclado
  6. 6
    ExemploConverter o referencial de coordenadas
  7. 7
    DesafioInspecionar um clique após a rolagem
  8. 8
    Ideia-chaveEvitar que a passagem do ponteiro seja o único caminho
  9. 9
    ExemploCalcular um movimento de arraste
  10. 10
    ExplicaçãoArmazenar o início e capturar seu ponteiro
  11. 11
    ExemploAplicar o deslocamento a cada movimento
  12. 12
    DicaEncerrar mesmo se o navegador assumir o controle
  13. 13
    DesafioPrever a continuação de um arraste
  14. 14
    ConexãoOferecer movimento sem arrastar
  15. 15
    DesafioDiagnosticar duas falhas de arraste
  16. 16
    RecapitulaçãoAssociar o evento à tarefa
4

Construir uma interação completa de formulário

16 passos
Leia campos, trate o envio e oriente a correção por meio de validação nativa e personalizada.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoAcompanhar um formulário da edição ao envio
  2. 2
    ExemploLer um número sem concatenação
  3. 3
    ExplicaçãoLer escolhas e nomes repetidos
  4. 4
    DesafioPreservar cada tópico selecionado
  5. 5
    ExplicaçãoTratar o envio no formulário
  6. 6
    ExemploLer, adicionar e redefinir
  7. 7
    DesafioManter o caminho normal de envio
  8. 8
    ExemploLer falhas de restrições independentes
  9. 9
    Ideia-chaveUm padrão não exige um valor
  10. 10
    DesafioVerificar um intervalo com incrementos
  11. 11
    ExplicaçãoAdicionar uma regra que conecta dois campos
  12. 12
    DicaSeparar validade do momento de exibição do erro
  13. 13
    DesafioCorrigir uma regra de data desatualizada
  14. 14
    ConexãoAssumir a responsabilidade ao ignorar o feedback do navegador
  15. 15
    DesafioCompletar o fluxo de recuperação
  16. 16
    RecapitulaçãoVerificar caminhos válidos e inválidos
5

Construir controles e preservar a posição do teclado

14 passos
Escolha o comportamento nativo, sincronize o estado personalizado e gerencie o foco durante mudanças na página.

Salve esta aula para seguir cada Lição Interativa passo a passo.

  1. 1
    IntroduçãoFazer uma interação funcionar pelo teclado
  2. 2
    ExplicaçãoUsar o comportamento que o HTML já fornece
  3. 3
    DicaDefinir a capacidade de foco para o caminho desejado
  4. 4
    DesafioCorrigir uma ação inacessível
  5. 5
    ExemploManter uma única função de ativação
  6. 6
    ExplicaçãoExpressar o tipo correto de estado
  7. 7
    DesafioInverter corretamente um controle de expansão e recolhimento
  8. 8
    ExemploMover uma parada de Tab dentro de um grupo
  9. 9
    ConexãoLembrar de onde uma caixa de diálogo veio
  10. 10
    ExemploManter interno um movimento de foco
  11. 11
    DesafioEscolher o foco após a remoção
  12. 12
    DesafioRastrear uma atualização de grupo
  13. 13
    DesafioManter um pop-up previsível
  14. 14
    RecapitulaçãoTestar a sequência completa do controle

Questões de Eventos e páginas interativas

50 Questões de Prática em 5 conjuntos

Conjunto 1: Tratar entradas de teclado, ponteiro e arraste10 Questões de Prática

Questão 1 de 10

Um atalho deve acompanhar a letra produzida em diferentes disposições de teclado. Qual propriedade ele deve testar?
  1. event.code
  2. event.repeat
  3. event.button
  4. event.key
Mostrar respostaOcultar resposta
Resposta: D
key descreve o valor produzido pela disposição atual do teclado e pelos modificadores, então é adequado para um atalho baseado no significado de uma letra. code descreve a posição física da tecla. Escolher essa posição manteria um controle de jogo no lugar, mas não acompanharia a letra produzida em diferentes disposições.

Questão 2 de 10

Uma prévia não detecta texto colado por um menu de contexto e mostra a digitação com um caractere de atraso. Atualmente, ela lê o campo em keydown. Qual mudança resolve os dois sintomas?
  1. Ler o campo em um ouvinte de keyup.
  2. Ler event.code no ouvinte de keydown.
  3. Ler o campo em um ouvinte de input.
  4. Chamar preventDefault() para cada keydown.
Mostrar respostaOcultar resposta
Resposta: C
input é executado após a edição do campo e inclui colagem sem pressionamento de uma tecla física. Portanto, ele corrige tanto o momento da leitura quanto a edição não detectada. keyup pode ser executado após a digitação, mas uma colagem pelo menu de contexto não exige a liberação de uma tecla, então esse caminho ainda não seria detectado.

Questão 3 de 10

Um atalho no documento para “n” sem modificadores deve abrir um painel uma vez por pressionamento sem interromper a entrada de texto. Manter N pressionado em um div editável atualmente o abre repetidamente. Quais condições devem ser verificadas antes da abertura?
  1. Ignorar alvos editáveis e chamadas repetidas de keydown.
  2. Ignorar apenas chamadas repetidas; permitir todos os alvos editáveis.
  3. Ignorar apenas elementos input; permitir todas as chamadas repetidas.
  4. Cancelar primeiro todas as teclas e depois ignorar alvos editáveis.
Mostrar respostaOcultar resposta
Resposta: A
O div editável deve ser excluído por meio de isContentEditable, junto com alvos input, textarea e select. O indicador repeat filtra as chamadas de tecla mantida pressionada para que um novo pressionamento aja uma vez. Cancelar todas as teclas antes de verificar o alvo ainda interromperia a digitação, mesmo quando a ação do painel fosse ignorada.

Questão 4 de 10

A ação de um botão nativo funciona com mouse, mas não quando ativada com a barra de espaço. Seu único ouvinte usa pointerdown. Qual evento deve tratar a ação?
  1. pointermove
  2. click
  3. mousedown
  4. pointerenter
Mostrar respostaOcultar resposta
Resposta: B
Um botão nativo emite click tanto para ativação pelo teclado quanto por ponteiro. Tratar esse evento dá à ação um caminho comum. Substituir pointerdown por mousedown manteria a ação ligada ao pressionamento de um dispositivo apontador e ainda deixaria de captar o clique nativo pelo teclado.

Questão 5 de 10

O documento foi rolado 420 px para baixo. Um evento de ponteiro informa clientY 75. Qual é sua coordenada vertical em relação ao documento?
  1. 495 px
  2. 345 px
  3. 75 px
  4. 420 px
Mostrar respostaOcultar resposta
Resposta: A
O pageY relativo ao documento inclui o deslocamento de rolagem, então a posição é 420 mais 75, ou 495 px. Manter 75 descreveria apenas a posição na área de visualização. Subtrair o deslocamento de rolagem segue a direção errada ao converter coordenadas da área de visualização para coordenadas do documento.

Questão 6 de 10

Um cartão de ajuda oculta sua dica quando o ponteiro se move do fundo do cartão para um indicador filho. Seu ouvinte de ocultação usa pointerout. Qual evento detecta melhor a saída do cartão inteiro?
  1. pointerover
  2. pointermove
  3. pointerleave
  4. pointerdown
Mostrar respostaOcultar resposta
Resposta: C
pointerleave descreve a saída do cartão como um todo, incluindo seus filhos. pointerout pode disparar nas transições pelos limites dos filhos, explicando por que entrar no indicador oculta a dica. A dica ainda precisa de um caminho acessível, como foco ou clique, para pessoas que não passam o ponteiro.

Questão 7 de 10

Uma caixa começa em left: 65px; top: 90px. Seu ponteiro começa em 180, 210 e se move para 155, 245 em coordenadas de cliente. A que posição a caixa deve chegar?
  1. left: 155px; top: 245px
  2. left: 90px; top: 55px
  3. left: 25px; top: 35px
  4. left: 40px; top: 125px
Mostrar respostaOcultar resposta
Resposta: D
O ponteiro moveu 25 px para a esquerda e 35 px para baixo. Some esses deslocamentos à posição inicial da caixa para obter 40 px à esquerda e 125 px no topo. Atribuir as coordenadas do ponteiro diretamente ignoraria onde a caixa começou e onde o ponteiro foi pressionado dentro dela, causando um salto.

Questão 8 de 10

Uma caixa armazena as posições iniciais corretas e captura seu primeiro toque. Um segundo toque então sobrescreve as posições iniciais, e soltar qualquer um dos toques encerra o movimento. Qual mudança no estado resolve as duas falhas?
  1. Capturar cada novo ponteiro e sobrescrever as posições a cada pressionamento.
  2. Armazenar o ID do ponteiro ativo e verificar pressionamento, movimento e término.
  3. Usar coordenadas de página e deixar qualquer ponteiro encerrar a interação.
  4. Ignorar pointercancel e manter passivos todos os ouvintes de movimento.
Mostrar respostaOcultar resposta
Resposta: B
Um único ID de ponteiro ativo permite que o código ignore um segundo pressionamento durante o arraste, ignore movimentos de outros ponteiros e encerre apenas para seu próprio ponteiro. A captura encaminha os eventos de um ponteiro; ela não filtra automaticamente ponteiros não relacionados. Mudar os referenciais de coordenadas não corrige o estado sobrescrito por um segundo contato.

Questão 9 de 10

Um arraste por toque tem captura de ponteiro e cálculos corretos, mas um gesto de rolagem do navegador o cancela. O próximo movimento do ponteiro ainda pode mover a caixa. Qual par de mudanças resolve o controle do gesto e o estado desatualizado?
  1. Aplicar user-select: none localmente; limpar o estado apenas em pointerup.
  2. Capturar o ponteiro novamente a cada movimento; ignorar o cancelamento.
  3. Aplicar touch-action: none localmente; limpar o estado em pointercancel.
  4. Cancelar todo keydown no documento; limpar o estado ao soltar uma tecla.
Mostrar respostaOcultar resposta
Resposta: C
touch-action: none aplicado localmente informa ao navegador que a superfície de arraste controla esse gesto de toque. Limpar o estado ativo em pointercancel também trata qualquer cancelamento que ainda ocorra. A captura de ponteiro, por si só, encaminha eventos de ponteiro; ela não reserva gestos do navegador nem limpa o estado de arraste da aplicação.

Questão 10 de 10

Uma lista reordenável permite arraste e movimento por teclas de seta. Um usuário de toque não consegue arrastar com precisão. Qual adição oferece a esse usuário uma alternativa adequada?
  1. Botões de movimento que possam ser clicados ou tocados.
  2. Uma alça de arraste maior em cada item.
  3. Instruções que descrevam as teclas de seta.
  4. Um menu disponível apenas pela passagem do ponteiro com dicas de movimento.
Mostrar respostaOcultar resposta
Resposta: A
Botões de movimento permitem reordenar com cliques ou toques individuais e também podem ser ativados pelo teclado. O suporte às teclas de seta oferece acesso pelo teclado, mas não fornece, por si só, uma alternativa com um único ponteiro para esse usuário de toque. Uma alça maior ainda exige o mesmo movimento de arraste.
Conjunto 2: Configurar e inspecionar ouvintes de eventos10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

Um ouvinte de clique está registrado em um botão que contém um span. O span é clicado. Quais são target e currentTarget durante a execução desse ouvinte?
  1. target: botão; currentTarget: span.
  2. target: span; currentTarget: botão.
  3. target: span; currentTarget: span.
  4. target: botão; currentTarget: botão.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

Um botão deve chamar showHints apenas quando for ativado. Qual registro consegue isso?
  1. button.addEventListener("click", showHints());
  2. button.addEventListener("click", showHints);
  3. button.addEventListener("onclick", showHints);
  4. button.addEventListener("click", () => showHints);
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

Um script no head seleciona um botão cuja marcação aparece depois e falha em addEventListener. Qual mudança no carregamento permite que a seleção espere até a análise sintática do HTML?
  1. Renomear o parâmetro do ouvinte para event.
  2. Usar onclick como nome do evento registrado.
  3. Mover a seleção para uma chamada imediata de função.
  4. Adicionar defer à tag do script externo.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

Um script externo usa const items = document.querySelectorAll(".choice"); items.addEventListener("click", choose);. Todas as opções já existem. Por que isso falha e como a configuração deve mudar?
  1. O resultado é uma NodeList; registre em cada item.
  2. O resultado é uma NodeList; use o nome de evento "onclick".
  3. Faltam parênteses na função de retorno; registre choose() na lista.
  4. O resultado é um elemento; registre nele um ouvinte de captura.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

Duas funções distintas são atribuídas em ordem: button.onclick = first; button.onclick = second;. O que acontece quando o botão é clicado uma vez?
  1. first é executada, seguida de second.
  2. Apenas first é executada.
  3. Apenas second é executada.
  4. second é executada, seguida de first.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

Um ouvinte definido com função de seta em <button data-code="r8"><span>Run</span></button> lê event.target.dataset.code. Por que ele pode retornar undefined e qual expressão, em um ouvinte direto, lê o código do botão?
  1. O span pode ser o alvo; leia event.currentTarget.dataset.code.
  2. O botão perde seus dados; leia event.type.dataset.code.
  3. O span pode ser o alvo; leia this.dataset.code na função de seta.
  4. O botão é o alvo; leia event.currentTarget.value.code.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

Um ouvinte registra seu objeto de evento. Após o término da interação, expandir o registro mostra currentTarget: null. Como a pessoa desenvolvedora pode inspecionar o elemento do ouvinte durante a chamada?
  1. Ler event.target após a chamada como o elemento do ouvinte.
  2. Adicionar once: true para que o objeto mantenha seu alvo atual.
  3. Registrar o objeto de evento novamente após o disparo terminar.
  4. Registrar event.currentTarget dentro do ouvinte.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

Uma função de retorno foi registrada com { capture: true }. O mesmo tipo e a mesma função são passados a removeEventListener, mas nenhum terceiro argumento é fornecido. Por que a função de retorno permanece?
  1. A remoção exige que todas as opções originais sejam repetidas.
  2. Funções de captura só podem ser removidas com abort().
  3. A remoção procura o registro que não usa captura.
  4. A remoção compara o texto da função em vez de sua identidade.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

Cada clique em “Iniciar” registra board.addEventListener("click", () => mark()). Iniciar duas vezes faz um clique no tabuleiro colocar duas marcas. Qual mudança na configuração impede esse acúmulo?
  1. Adicionar once: true a cada nova função de retorno do tabuleiro.
  2. Remover uma nova () => mark() antes de adicioná-la.
  3. Definir board.onclick = null antes de adicionar cada função de retorno.
  4. Registrar uma função de retorno salva na configuração inicial.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

Um botão sem outros ouvintes recebe estes registros e depois é clicado duas vezes. Quantas vezes log é executada no total?

button.addEventListener("click", log, { once: true });
button.addEventListener("click", log);
button.addEventListener("click", log, true);
button.removeEventListener("click", log);
  1. 2
  2. 1
  3. 3
  4. 4
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Conjunto 3: Rastrear ações aninhadas e delegação10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

Um ouvinte de link chama apenas event.stopPropagation(). O que acontece com sua navegação normal?
  1. A navegação é cancelada.
  2. O link ainda navega.
  3. O link precisa de dois cliques.
  4. Ouvintes ancestrais o bloqueiam.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

Um botão está dentro de uma seção que está dentro de um elemento main. Cada um tem um ouvinte de clique comum. Qual é a ordem de execução quando o botão é clicado?
  1. Main → seção → botão.
  2. Seção → botão → main.
  3. Botão → seção → main.
  4. Botão → main → seção.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

Um contêiner tem ouvintes de clique de captura e comum. Seu botão filho tem um ouvinte de clique comum. O que é registrado quando o botão é clicado?
  1. Captura no contêiner → botão → comum no contêiner.
  2. Botão → captura no contêiner → comum no contêiner.
  3. Comum no contêiner → botão → captura no contêiner.
  4. Captura no contêiner → comum no contêiner → botão.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

Um formulário tem um ouvinte comum de focus, mas dar foco ao seu input filho não o chama. Como o formulário pode observar o foco em descendentes sem usar captura?
  1. Ouvir blur no formulário.
  2. Adicionar bubbles: true como opção do ouvinte.
  3. Ler currentTarget na função de retorno de foco existente.
  4. Ouvir focusin no formulário.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

Um ouvinte de envio de formulário chama preventDefault(). Também existe um ouvinte comum de envio em uma seção que o envolve. O que o ouvinte da seção pode observar?
  1. Ele é ignorado porque o cancelamento interrompe o borbulhamento.
  2. Ele é executado e lê defaultPrevented como falso.
  3. Ele é executado apenas se também chamar preventDefault().
  4. Ele é executado e pode ler defaultPrevented como verdadeiro.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

Um botão abre um menu. Um ouvinte de clique no documento o fecha no mesmo clique. O menu também deve fechar em cliques realmente externos, e o registro no nível do documento deve continuar funcionando. Qual mudança atende às três necessidades?
  1. Fechar apenas quando nem o menu nem seu controle de abertura contiver o alvo.
  2. Interromper a propagação em todo clique no botão do menu antes de abri-lo.
  3. Cancelar o clique no botão do menu antes de alternar o estado oculto.
  4. Fechar apenas quando o próprio menu não contiver o alvo.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

Um ouvinte delegado em uma barra de ferramentas recebe um clique cujo alvo é um SVG dentro de um botão. Qual expressão encontra o botão a partir desse alvo?
  1. event.target.closest("button")
  2. event.currentTarget.closest("button")
  3. event.target.matches("button")
  4. event.target.querySelector("button")
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

Uma lista vazia recebe um ouvinte de clique delegado. Depois, o código acrescenta um botão de remoção correspondente dentro de um item. Qual registro é necessário para o novo botão?
  1. Registrar também a mesma função de retorno no novo botão.
  2. Nenhum novo registro; seu clique alcança a lista.
  3. Remover e adicionar novamente o ouvinte da lista após a inserção.
  4. Disparar DOMContentLoaded novamente após adicionar o botão.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

Um ouvinte delegado usa closest(".action") dentro de um contêiner aninhado em um elemento externo .action. Um clique em um espaço vazio encontra esse elemento externo. Qual verificação mantém o tratamento local?
  1. Retornar quando event.currentTarget === container.
  2. Retornar apenas quando a correspondência for igual a event.target.
  3. Retornar quando a correspondência não tiver elementos filhos.
  4. Retornar quando a correspondência estiver fora de container.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

Uma lista delega cliques de remoção com closest(".remove") e verificações de pertencimento. Novos botões funcionam, exceto em uma linha cujo ouvinte do ícone chama stopPropagation(). Clicar na área de preenchimento do botão da mesma linha funciona. Por que ocorre essa diferença?
  1. A verificação de pertencimento rejeita todo SVG descendente.
  2. Novas linhas precisam de ouvintes diretos em todos os ícones.
  3. Cliques no ícone são interrompidos antes de chegar à lista.
  4. closest busca para baixo quando o alvo é um ícone.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Conjunto 4: Ler dados de formulário e diagnosticar a validação10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

Uma entrada numérica contém "6". O que input.value + 2 produz?
  1. A cadeia de caracteres "62".
  2. O número 8.
  3. O número 62.
  4. A cadeia de caracteres "8".
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

Um formulário tem entradas de tópico marcadas chamadas topic, com valores "art" e "code" na ordem do documento, uma entrada topic não marcada com valor "music" e uma nota desabilitada com nome. O que new FormData(form).getAll("topic") retorna e por que a conversão para objeto é arriscada?
  1. ["art", "code", "music"]; a conversão para objeto mantém apenas o primeiro nome repetido.
  2. ["art", "code"]; a conversão para objeto adiciona controles desabilitados à coleção.
  3. ["code"]; a conversão para objeto reúne todos os valores de tópico em um vetor.
  4. ["art", "code"]; a conversão para objeto mantém apenas o último nome repetido.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

Um botão “Mostrar detalhes” dentro de um formulário deve apenas revelar um painel. Qual tipo explícito impede que ele envie o formulário?
  1. type="submit"
  2. type="reset"
  3. type="text"
  4. type="button"
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

Um formulário tem um campo obrigatório vazio. Uma barra de ferramentas chama form.submit(), e o ouvinte do formulário que impede a navegação nunca é executado. Qual chamada restaura o fluxo esperado e o que acontece antes de esse campo ser corrigido?
  1. Use requestSubmit(); o ouvinte de envio é executado antes de a validação bloqueá-lo.
  2. Use submit() novamente; a segunda chamada executa o ouvinte após a validação.
  3. Use requestSubmit(); a validação bloqueia o envio antes de submit disparar.
  4. Use dispatchEvent(new Event("submit")); ele executa a validação nativa normal.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

Uma entrada de texto tem pattern="[A-Z]{3}" e é opcional. Um valor vazio passa nessa restrição de padrão?
  1. Não; todo padrão implica uma entrada obrigatória.
  2. Sim; o padrão ignora valores vazios.
  3. Não; o valor vazio causa typeMismatch.
  4. Sim; o padrão se aplica apenas a dígitos digitados.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

Um campo numérico tem min="2" max="14" step="4". O usuário insere 12. O que falha?
  1. stepMismatch, porque os incrementos permitidos são 2, 6, 10, 14.
  2. rangeOverflow, porque 12 ultrapassa o último incremento abaixo de 14.
  3. Nenhuma restrição; 12 está entre o mínimo e o máximo.
  4. rangeUnderflow, porque o incremento começa em zero.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

Um formulário usa novalidate e verifica os campos na ordem do documento durante o envio. Sua quantidade é obrigatória e tem min="2" max="14" step="4"; agora contém 10 e uma mensagem personalizada antiga foi limpa com setCustomValidity(""). O campo seguinte é um e-mail obrigatório que está vazio. O que deve bloquear essa tentativa e receber foco?
  1. A quantidade, porque limpar uma mensagem personalizada a deixa inválida.
  2. O e-mail, porque está ausente; a quantidade atende às suas restrições.
  3. Nenhum dos campos, porque novalidate desativa a API de validade.
  4. A quantidade, porque 10 não segue o incremento de quatro a partir do mínimo.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

Uma confirmação de senha estava inválida. Os valores agora coincidem, mas uma mensagem antiga e não vazia de validade personalizada permanece. O que a função de verificação deve fazer?
  1. Definir confirm.value novamente como ele mesmo.
  2. Definir apenas confirm.required = false.
  3. Chamar confirm.setCustomValidity("").
  4. Chamar form.requestSubmit() repetidamente.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

Uma reserva exige uma data final não vazia estritamente posterior à data inicial. Ambas as entradas de data são obrigatórias. A verificação atual rejeita apenas end.value < start.value e é executada apenas em edições da data final. Quais duas mudanças corrigem as falhas restantes entre os campos?
  1. Rejeitar <= e verificar novamente quando qualquer data mudar.
  2. Rejeitar < e verificar novamente apenas quando a data final perder o foco.
  3. Rejeitar >= e verificar novamente quando qualquer data mudar.
  4. Rejeitar === e verificar novamente apenas quando a data inicial perder o foco.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

Uma mensagem de e-mail inválido aparece enquanto o campo está sendo corrigido. Qual sequência a remove rapidamente sem mostrar erros desde a primeira tecla em campos ainda não tocados?
  1. Verificar novamente apenas na perda de foco, mesmo após mostrar um erro.
  2. Mostrar todos os campos vazios como incorretos no carregamento inicial.
  3. Limpar todas as mensagens em qualquer keydown antes de ler a validade.
  4. Verificar erros informados em input; iniciar o feedback na perda de foco ou no envio.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Conjunto 5: Construir acesso pelo teclado e preservar o foco10 Questões de Prática

Salve esta aula para ver todas as respostas e praticar cada conjunto.

Questão 1 de 10

Um div tem role="button" e um ouvinte de clique. O que o próprio papel fornece?
  1. Uma parada normal de Tab e um contorno de foco visível.
  2. Semântica de botão para tecnologia assistiva.
  3. Ativação com Enter e barra de espaço sem código adicional.
  4. Comportamento nativo de desabilitação a partir de aria-disabled.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 2 de 10

Um título de erro de formulário deve receber foco após um envio malsucedido, mas não deve acrescentar uma parada durante a navegação normal por Tab. Qual configuração é adequada?
  1. Definir tabindex="1" e chamar .focus().
  2. Definir role="alert" e depender do foco por Tab.
  3. Definir tabindex="-1" e chamar .focus().
  4. Definir tabindex="0" e remover seu contorno.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 3 de 10

Um botão personalizado que pode receber foco encaminha click e keydown para activate(). Ele tem aria-disabled="true". A função começa com if (button.getAttribute("aria-disabled") === true) return;, mas os dois caminhos ainda executam a ação. Qual correção faz valer o estado desabilitado e permite a ação no estado da cadeia de caracteres “false”?
  1. Comparar com "true" dentro da função de ativação compartilhada.
  2. Testar o valor avaliado como verdadeiro do atributo retornado dentro de activate.
  3. Comparar com o booleano verdadeiro apenas no ouvinte de clique.
  4. Mover a verificação inalterada para um ouvinte de pointerdown.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 4 de 10

Um botão personalizado de expansão e recolhimento abre um painel de ajuda. Qual atributo ARIA informa se esse painel está aberto?
  1. aria-checked
  2. aria-pressed
  3. aria-disabled
  4. aria-expanded
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 5 de 10

Um controle de expansão e recolhimento tem atualmente aria-expanded="true" e um painel visível. Seu tratador de clique lê o estado expandido anterior. Qual deve ser o próximo estado?
  1. aria-expanded="true"; panel.hidden = true.
  2. aria-expanded="false"; panel.hidden = false.
  3. aria-expanded="true"; panel.hidden = false.
  4. aria-expanded="false"; panel.hidden = true.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 6 de 10

Uma barra de ferramentas com quatro itens usa tabindex itinerante. O item 0 está com foco. Após ArrowLeft, quais mudanças de índice e tabindex mantêm a navegação funcionando?
  1. Dar foco a −1; manter o item 0 em 0 e todos os outros em −1.
  2. Dar foco a 3; definir o item 0 como −1 e o item 3 como 0.
  3. Dar foco a 3; manter tanto o item 0 quanto o item 3 em 0.
  4. Dar foco a 1; definir o item 0 como 0 e o item 1 como −1.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 7 de 10

Um botão de alternância nativo chama a mesma função de inversão em click e em keydown de Enter. Enter deixa seu estado pressionado inalterado, enquanto um clique de ponteiro o alterna uma vez. Qual mudança corrige o caminho do teclado sem perder o acesso?
  1. Manter a ação de click e remover a ativação extra de Enter.
  2. Manter os dois ouvintes e adicionar uma inversão em keydown da barra de espaço.
  3. Substituir click por pointerdown e não manter um ouvinte de teclado.
  4. Manter os dois ouvintes e chamar preventDefault após cada click.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 8 de 10

Uma caixa de diálogo modal fecha enquanto seu controle de abertura ainda existe. Para onde o foco normalmente deve retornar?
  1. Para o corpo da página após cada fechamento.
  2. Para o primeiro link do documento.
  3. Para o controle que a abriu.
  4. Para o botão de fechamento oculto da caixa de diálogo.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 9 de 10

Um pop-up tem dois campos. O foco se move do primeiro para o segundo, e um ouvinte de focusout que borbulha oculta o pop-up. O que o ouvinte deve verificar antes de ocultá-lo?
  1. Se relatedTarget está fora do pop-up.
  2. Se target é igual ao primeiro campo.
  3. Se currentTarget é igual ao pop-up.
  4. Se a tecla usada para mover foi Tab.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Questão 10 de 10

Uma lista tem dois itens e um título com tabindex="-1". O botão de exclusão com foco no último item remove esse item; depois, o item restante também é excluído. Qual sequência de foco permite continuar usando o teclado?
  1. Primeiro o corpo da página, depois o botão excluído anteriormente.
  2. Primeiro o botão do item anterior, depois o título da lista.
  3. Primeiro o título, depois o próximo irmão do item removido.
  4. Primeiro o botão removido, depois o primeiro link do documento.
Mostrar respostaOcultar resposta

Salve esta aula para ver esta resposta.

Travou em uma questão sua? Ajuda com Tarefas

Termos-Chave

80 Termos-Chave, cada um com sua definição

A

Ação padrão
Uma ação padrão é um comportamento fornecido pelo navegador e associado a um evento, como seguir um link, inserir texto ou enviar um formulário.
A ação padrão do link de ajuda seria navegar até seu destino, a menos que o clique fosse cancelado.
Alternativa com um único ponteiro
Uma alternativa com um único ponteiro executa uma função de arraste por meio de cliques ou toques sem exigir que o ponteiro permaneça pressionado durante o movimento.
Botões de movimento permitem que um usuário de toque reposicione um item sem realizar um gesto de arraste.
Ativação
Ativação é a solicitação do usuário para executar a ação de um controle, representada por click para uso com ponteiro e teclado nativo.
Um botão nativo de avançar responde por meio de click quando pressionado com a barra de espaço ou com o mouse.
Atributo aria-describedby
O atributo aria-describedby associa um controle a um texto descritivo listando os IDs dos elementos que contêm esse texto.
O campo de e-mail faz referência a email-error para que a tecnologia assistiva possa associar o erro a ele.
Atributo aria-invalid
O atributo aria-invalid comunica que o valor inserido em um controle tem um erro; o código deve atualizá-lo conforme o erro muda.
O campo de e-mail tem aria-invalid="true" enquanto sua mensagem de correção em linha é exibida.
Atributo de dados
Um atributo de dados é um atributo HTML que começa com data- e armazena informações da aplicação disponíveis por meio do dataset de um elemento.
Uma barra de ferramentas lê data-action="clear" como button.dataset.action para selecionar uma ação conhecida.
Atributo novalidate
O atributo de formulário novalidate ignora a validação automática de restrições durante o envio, mantendo disponíveis as restrições e os métodos de validade.
Um fluxo de erro personalizado usa novalidate para que seu ouvinte de envio possa inspecionar cada campo.
Atributo pattern
O atributo pattern define uma restrição de expressão regular para o valor inteiro de entradas de texto compatíveis, aplicada apenas quando seu valor não está vazio.
Um padrão de cinco dígitos rejeita seis dígitos, mas precisa de required para rejeitar um campo vazio.
Atributo tabindex
O atributo tabindex controla a participação normal na navegação por Tab e a capacidade de receber foco por código, com 0 na ordem normal e −1 fora dessa sequência.
O título de erro usa tabindex="-1" para que o código possa lhe dar foco sem adicionar uma parada comum de Tab.

B

Borbulhamento
Borbulhamento é o percurso de subida de um evento pelos ancestrais após a fase do alvo, disponível apenas para eventos cujo valor bubbles é verdadeiro.
O evento input de um campo filho borbulha até um ouvinte registrado no formulário que o contém.
Botão de alternância
Um botão de alternância liga ou desliga o estado de uma ação, normalmente usando um rótulo visível fixo e aria-pressed para informar o estado atual.
Um botão de silenciar mantém a palavra “Silenciar” enquanto seu valor aria-pressed muda entre verdadeiro e falso.
Botão responsável pelo envio
O botão responsável pelo envio é o botão de envio usado em uma submissão, exposto como event.submitter quando um botão específico iniciou esse caminho.
Um formulário distingue rascunho e publicação lendo o valor do botão que o enviou.

C

Caixa de diálogo modal
Uma caixa de diálogo modal é uma interação de diálogo que torna o restante da página inerte enquanto está aberta, limitando a interação do usuário à sua área ativa.
Chamar showModal() abre a caixa de diálogo nativa e move o foco para seu conteúdo.
Captura de ponteiro
A captura de ponteiro direciona eventos posteriores de um ponteiro ativo especificado a um elemento mesmo depois que o ponteiro se move para fora de seus limites.
Uma caixa arrastada captura o ponteiro que iniciou o arraste para que um movimento rápido não saia de sua área de eventos.
Coleção FormData
FormData é uma coleção de pares de nome e valor de formulário que podem ser incluídos, preserva nomes repetidos e omite controles que não são enviados.
Quando várias caixas de seleção compartilham o nome “topics”, data.getAll("topics") obtém juntas todas as marcadas.
Conteúdo de fundo inerte
Conteúdo de fundo inerte é o conteúdo da página temporariamente indisponível para cliques e foco comuns enquanto uma interação modal está ativa.
A página atrás de uma caixa de diálogo modal nativa aberta não pode receber foco normal até que ela seja fechada.
Controlador de cancelamento
Um AbortController fornece um sinal que pode agrupar períodos de atividade de ouvintes, removendo os ouvintes associados quando seu método abort() é chamado.
Fechar uma ferramenta de desenho cancela o sinal usado por seus ouvintes no documento e na janela.
Controle de abertura
Um controle de abertura é o controle que inicia uma interação de pop-up ou caixa de diálogo e geralmente é o destino adequado do foco quando essa interação termina.
A caixa de diálogo armazena o botão de abertura para poder restaurar o foco após o evento de fechamento.
Controle de expansão e recolhimento
Um controle de expansão e recolhimento é um controle com um painel que revela ou oculta conteúdo, cujo botão comunica seu estado por meio de aria-expanded.
Um botão de detalhes muda seu estado expandido junto com a visibilidade do painel de ajuda que ele controla.
Controle nativo
Um controle nativo é um elemento HTML com semântica e comportamento de interação integrados, como botão, link, caixa de seleção ou lista de seleção.
Um botão nativo estilizado mantém sua ativação por Enter e barra de espaço sem um ouvinte de teclado personalizado.
Coordenadas da área de visualização
Coordenadas da área de visualização são posições do ponteiro medidas a partir do canto superior esquerdo da área visível por meio de clientX e clientY.
Um cálculo de movimento subtrai duas leituras de coordenadas de cliente sem adicionar a rolagem da página.
Coordenadas do documento
Coordenadas do documento são posições do ponteiro medidas a partir do canto superior esquerdo do documento por meio de pageX e pageY, incluindo a rolagem.
Um clique 100 px abaixo do topo da área de visualização após 300 px de rolagem tem pageY 400.

D

Delegação de eventos
A delegação de eventos trata eventos de vários descendentes por meio de um ouvinte em um ancestral comum que identifica o controle relevante.
O único ouvinte de clique de uma lista continua funcionando para novos botões de remoção inseridos posteriormente.
Disparo síncrono
O disparo síncrono significa que os ouvintes são executados dentro da chamada a dispatchEvent(), antes de esse método retornar o controle ao código que o chamou.
Uma mensagem registrada após dispatchEvent() aparece depois das mensagens de seus ouvintes.

E

Estado ARIA
Um estado ARIA é um valor de atributo que comunica a condição atual de um controle, como marcado, expandido, pressionado ou desabilitado.
O valor aria-checked do interruptor é atualizado quando sua aparência visível de ligado/desligado muda.
Estado de arraste
O estado de arraste é o conjunto de informações armazenadas que identifica um arraste ativo, suas coordenadas iniciais de ponteiro e a posição inicial do elemento.
Durante um arraste, cada movimento do ponteiro compara as coordenadas atuais com o início salvo para posicionar uma caixa arrastada.
Estado de validade (ValidityState)
Um ValidityState é o objeto exposto pela propriedade validity de um controle, com indicadores booleanos que identificam restrições não atendidas.
Uma quantidade pode informar stepMismatch mesmo estando entre seu mínimo e máximo.
Evento
Um evento é um sinal que informa algo que aconteceu, como um clique, uma edição de campo, o pressionamento de uma tecla ou a conclusão da análise sintática do HTML.
Um evento click permite que a página responda quando uma pessoa ativa o botão de avançar da galeria.
Evento change
Um evento change informa uma alteração confirmada pelo usuário, como sair de um campo de texto editado ou selecionar um novo estado em uma caixa de seleção ou lista de seleção.
Um campo de texto alterado dispara change quando o usuário sai dele para o próximo controle.
Evento de ponteiro
Um evento de ponteiro descreve uma interação com dispositivo apontador por meio de uma família de eventos compartilhada por entradas de mouse, toque e caneta.
O mesmo ouvinte de pointermove pode ler o movimento de um mouse ou de um contato por toque.
Evento input
Um evento input informa uma edição do usuário após o valor de um controle mudar, incluindo edições de texto feitas sem o pressionamento de uma tecla física.
Colar uma frase em um campo de mensagem atualiza um contador por meio do ouvinte de input do campo.
Evento keydown
Um evento keydown informa o pressionamento de uma tecla antes de seu efeito normal de edição e pode se repetir enquanto a tecla física permanece pressionada.
O atalho verifica se a tecla é Escape em keydown antes de fechar o painel aberto.
Evento personalizado
Um CustomEvent é um evento criado por script que pode carregar dados da aplicação em detail e ser configurado para borbulhar até os ancestrais.
Um item do carrinho dispara "cart:add" com seu identificador no detail do evento.
Evento pointercancel
Um evento pointercancel informa que o navegador cancelou a interação do ponteiro, exigindo que um arraste limpe seu estado ativo.
Um gesto assumido para rolagem pode encerrar o arraste personalizado por meio de pointercancel.
Evento submit
Um evento submit é um evento cancelável de formulário disparado durante o caminho normal de envio após a validação automática permitir o envio.
O ouvinte de submit de um formulário trata um envio válido adicionando um item localmente e cancelando a navegação.

F

Fase de captura
A fase de captura é o caminho de descida do evento pelos ancestrais em direção ao alvo, observado por ouvintes registrados para captura.
Um ouvinte de captura em um contêiner é executado antes de o ouvinte de um botão descendente tratar o clique.
Fase do alvo
A fase do alvo é a parte do disparo na origem do evento, onde ouvintes de captura são executados antes dos ouvintes que não usam captura.
Ambos os ouvintes no botão clicado informam eventPhase 2 enquanto são chamados.
Foco
Foco é o estado da página que identifica o elemento que recebe atualmente a entrada do teclado, disponível por meio de document.activeElement.
Chamar search.focus() direciona o próximo caractere digitado para o campo de busca.

G

Gerenciamento de foco
O gerenciamento de foco escolhe deliberadamente um destino útil para o teclado quando um conteúdo abre, fecha, desaparece ou apresenta erros ao usuário.
Excluir uma linha com foco move o foco para o controle de uma linha vizinha em vez de perder a posição.
Grupo composto
Um grupo composto é um conjunto relacionado de controles, como abas ou uma barra de ferramentas, navegado internamente com teclas de seta enquanto Tab entra e sai dele.
O grupo de abas mantém uma parada de Tab para que os usuários possam passar pelo grupo sem visitar cada aba.

I

Identidade do ouvinte
A identidade do ouvinte combina o tipo de evento, o objeto de função de retorno e a configuração de captura, determinando registros duplicados e remoções.
Uma nova função de seta não pode remover uma função de retorno anterior apenas porque seus corpos são iguais.
Indicador de foco
Um indicador de foco é uma marca visível que identifica o elemento atualmente com foco para que usuários de teclado possam localizar sua posição na página.
Um contorno :focus-visible mostra qual botão da barra de ferramentas receberá a próxima ação de teclado.
Indicador de tecla modificadora
Um indicador de tecla modificadora é uma propriedade booleana de evento de teclado que descreve se Shift, Control, Alt ou Meta está pressionada durante o evento.
O atalho de salvamento aceita ctrlKey ou metaKey junto com a letra S.

M

Máscara de bits dos botões
Uma máscara de bits dos botões representa os botões de ponteiro atualmente pressionados combinando indicadores numéricos na propriedade buttons do evento.
Manter os botões primário e secundário pressionados produz buttons 3, combinando os indicadores 1 e 2.
Método checkValidity
O método checkValidity() retorna se as restrições são atendidas e dispara eventos invalid para falhas sem exibir feedback do navegador.
Um fluxo personalizado de envio verifica o formulário antes de decidir quais erros em linha exibir.
Método closest
O método closest() verifica um elemento e depois seus ancestrais em busca da correspondência mais próxima com um seletor, retornando null se nenhuma existir.
A partir de um ícone, closest("button") encontra o botão de ação que o envolve.
Método contains
O método contains() testa se um nó é o próprio elemento ou um de seus descendentes, retornando um resultado booleano.
Um ouvinte delegado em uma lista verifica list.contains(button) antes de permitir a ação do botão.
Método preventDefault
O método preventDefault() cancela a ação padrão de um evento cancelável em um ouvinte não passivo sem interromper sua propagação.
Um ouvinte de envio chama preventDefault() antes de adicionar um item local sem navegar.
Método reportValidity
O método reportValidity() verifica restrições e também solicita que o navegador exiba feedback de validação para falhas não tratadas.
Um botão de verificação explícita chama reportValidity() para ajudar o usuário a encontrar um campo que falha.
Método requestSubmit
O método requestSubmit() solicita o envio de um formulário pelo caminho normal de validação e evento de envio sem disparar um clique no botão.
Uma barra de ferramentas chama form.requestSubmit() para que a validação e o ouvinte de envio do formulário ainda sejam executados.
Método stopImmediatePropagation
O método stopImmediatePropagation() interrompe o percurso do evento e também pula os ouvintes restantes registrados no alvo atual do evento.
Quando a primeira função de retorno chama esse método, uma função posterior no mesmo elemento é ignorada.
Método stopPropagation
O método stopPropagation() impede que um evento percorra outros elementos, mantendo ativos os demais ouvintes no elemento atual.
Uma ação aninhada pode impedir que seu clique alcance o ouvinte de borbulhamento do cartão que a envolve.

N

Nome acessível
Um nome acessível é o texto que a tecnologia assistiva usa para identificar um controle, fornecido por conteúdo adequado, um rótulo ou um nome ARIA.
Um botão de fechar apenas com ícone usa aria-label="Close" para informar o que seu símbolo faz.

O

Objeto de evento
Um objeto de evento é o valor passado a um ouvinte que contém propriedades compartilhadas de eventos e detalhes específicos daquela família de eventos.
Um ouvinte de teclado lê a propriedade key do evento recebido para decidir se fecha um painel.
Opção once
A opção de ouvinte once solicita a remoção automática desse registro após sua primeira chamada para o tipo de evento selecionado.
Um banner de boas-vindas pode usar once: true para o clique que o dispensa durante esse período de uso.
Ouvinte de evento
Um ouvinte de evento é uma função registrada em um alvo de evento para que possa ser executada quando um tipo especificado de evento for disparado nele.
O ouvinte do contador aumenta o total armazenado sempre que seu botão recebe um clique.
Ouvinte passivo
Um ouvinte passivo é um ouvinte registrado com a promessa de não cancelar a ação padrão, permitindo que o navegador prossiga sem esperar pelo cancelamento.
Chamar preventDefault() em um ouvinte passivo de toque não interrompe a rolagem do navegador.

P

Papel ARIA
Um papel ARIA comunica a finalidade de um elemento à tecnologia assistiva sem acrescentar o comportamento de teclado ou as regras de foco correspondentes.
Um div com role="button" ainda precisa de código para ativação e de uma parada de Tab adequada.
Propagação
Propagação é o percurso de um evento pela árvore do documento, incluindo o caminho de captura, a fase do alvo e qualquer caminho de borbulhamento.
Um clique em um botão pode ser observado por ouvintes tanto no botão quanto no cartão que o envolve.
Propriedade cancelable
A propriedade cancelable é um booleano que indica se um evento permite o cancelamento de sua ação padrão por meio de preventDefault().
Um evento input informa uma edição já realizada, então sua propriedade cancelable é falsa.
Propriedade checked
A propriedade checked é o estado booleano que indica se uma caixa de seleção ou entrada de botão de opção está marcada, independentemente de seu valor de envio.
Uma prévia lê checkbox.checked para decidir se mostra uma seção opcional.
Propriedade code
A propriedade code identifica uma posição física de tecla independentemente do caractere produzido pela disposição atual do teclado.
Um jogo usa code quando seus controles de movimento devem permanecer em posições físicas fixas.
Propriedade CSS touch-action
A propriedade CSS touch-action declara quais gestos de toque do navegador são permitidos quando um gesto começa em um elemento.
Usar touch-action: none na superfície de arraste reserva o movimento nessa área para o arraste.
Propriedade currentTarget
A propriedade currentTarget identifica o objeto cujo ouvinte está sendo executado e é redefinida para null após o término do disparo do evento.
Dentro de um ouvinte registrado em um botão, currentTarget permite que o código leia os dados desse botão.
Propriedade de tratamento de evento
Uma propriedade de tratamento de evento é uma propriedade de elemento, como onclick, que armazena uma função de retorno de evento e a substitui quando recebe uma nova atribuição.
Atribuir outra função a button.onclick substitui o tratador anterior dessa propriedade.
Propriedade defaultPrevented
A propriedade defaultPrevented é um booleano que registra se a ação padrão de um evento foi cancelada com sucesso.
Um ouvinte ancestral pode inspecionar defaultPrevented antes de decidir como tratar um clique.
Propriedade key
A propriedade key informa o valor produzido por uma tecla, levando em conta a disposição do teclado e modificadores como Shift.
Shift pode mudar o valor key de uma letra de "a" para "A" enquanto sua posição permanece a mesma.
Propriedade pointerId
A propriedade pointerId identifica um ponteiro individual durante uma interação para que contatos simultâneos possam ser tratados separadamente.
Dois dedos têm IDs diferentes, permitindo que o código de arraste acompanhe apenas o que o iniciou.
Propriedade relatedTarget
A propriedade relatedTarget identifica o outro elemento envolvido em uma transição de foco ou é null quando não há esse elemento disponível.
Um ouvinte de focusout de um menu verifica se o destino permanece dentro do menu.
Propriedade target
A propriedade target identifica a origem do evento, que pode ser um elemento aninhado dentro do controle cuja ação está sendo tratada.
Clicar na imagem dentro de um botão de salvar faz da imagem o target do clique.
Propriedade value
A propriedade value expõe o valor atual de um controle de formulário como texto, incluindo entradas numéricas cujo conteúdo ainda precisa de conversão.
Um campo de quantidade que contém "8" precisa de conversão antes que o código adicione um incremento numérico.
Propriedade valueAsNumber
A propriedade valueAsNumber lê diretamente o valor numérico de uma entrada compatível e retorna NaN quando não há um valor numérico utilizável.
Um campo numérico vazio produz NaN, que o código detecta com Number.isNaN().

R

Redefinição do formulário
Uma redefinição do formulário restaura os valores e estados de seleção iniciais dos controles, que podem incluir valores padrão não vazios da marcação.
Depois que um formulário adiciona um item, form.reset() restaura os valores iniciais dos campos do formulário.
Referência a uma função
Uma referência a uma função é um valor que identifica um objeto de função, permitindo que o código passe essa função para uso posterior sem chamá-la.
Passar openPanel registra a função; passar openPanel() a chama durante a configuração.
Remoção de espaços em branco nas extremidades
A remoção de espaços em branco nas extremidades retira espaços em branco do início e do fim do texto antes que uma regra ou ação use seu conteúdo significativo.
Verificar name.value.trim() === "" detecta um nome composto inteiramente de espaços.
Resumo de erros
Um resumo de erros é uma região da página que reúne problemas de formulário e links para seus campos, fornecendo um destino de foco útil após uma falha.
Após um envio inválido, o resumo que pode receber foco permite que o usuário escolha qual campo corrigir.

T

tabindex itinerante
O tabindex itinerante é uma técnica de navegação em grupo que dá a um item uma parada normal de Tab e move essa parada e o foco conforme as teclas de seta mudam os itens.
Em uma barra de ferramentas, Tab entra no item atual e as teclas de seta movem o foco para os controles vizinhos.
Teste de clique fora
Um teste de clique fora verifica se um evento se originou fora tanto de um pop-up aberto quanto de seu controle de abertura antes de fechá-lo.
Um ouvinte do documento que ignora cliques no botão de um menu impede que o clique de abertura feche o menu.

V

Validação de restrições
A validação de restrições verifica se os valores de formulário satisfazem regras HTML, como entrada obrigatória, sintaxe de tipo, intervalos, incrementos e padrões.
Uma quantidade fora do intervalo bloqueia o envio normal antes de o ouvinte de envio do formulário ser executado.
Validade personalizada
Validade personalizada é uma restrição definida pela aplicação com setCustomValidity(), na qual uma mensagem não vazia marca o controle como inválido.
Uma confirmação divergente recebe uma mensagem personalizada que é limpa assim que as duas senhas coincidem.

Sobre esta aula

Por StudeliRelatar um erro

Crie seus próprios Materiais de Estudo

Transforme suas anotações, slides e documentos em Guias de Estudo, Questões de Prática, Flashcards e mais 6 ferramentas.

Começar