kb.erickguedes.com
HTML5: Estrutura e Semântica Web

Formulários e Acessibilidade

Aula 2 de 6

Formulários HTML5

HTML5 introduziu novos tipos de input, validação nativa e melhorias de experiência do usuário.

Novos Input Types

<form novalidate>
  <label for="email">E-mail:</label>
  <input type="email" id="email" name="email" required>

  <label for="tel">Telefone:</label>
  <input type="tel" id="tel" name="tel" pattern="[0-9]{10,11}">

  <label for="nascimento">Data de Nascimento:</label>
  <input type="date" id="nascimento" name="nascimento">

  <label for="idade">Idade:</label>
  <input type="range" id="idade" name="idade" min="0" max="120" value="25">

  <label for="cor">Cor Favorita:</label>
  <input type="color" id="cor" name="cor">

  <label for="busca">Busca:</label>
  <input type="search" id="busca" name="busca">

  <label for="url">Site:</label>
  <input type="url" id="url" name="url">

  <button type="submit">Enviar</button>
</form>

Validação Nativa

<form>
  <label for="senha">Senha (mín. 8 caracteres):</label>
  <input
    type="password"
    id="senha"
    name="senha"
    minlength="8"
    required
    pattern="^(?=.*[A-Z])(?=.*[a-z])(?=.*\d).{8,}$"
    title="Mínimo 8 caracteres, 1 maiúscula, 1 minúscula, 1 número"
  >

  <label for="arquivo">Currículo (PDF):</label>
  <input
    type="file"
    id="arquivo"
    name="arquivo"
    accept=".pdf"
    multiple
  >
</form>
// Validação customizada com Constraint Validation API
const form = document.querySelector('form');
const email = document.getElementById('email');

form.addEventListener('submit', (e) => {
  if (!email.validity.valid) {
    e.preventDefault();
    email.setCustomValidity(
      email.validity.valueMissing
        ? 'E-mail é obrigatório'
        : 'Formato de e-mail inválido'
    );
    email.reportValidity();
  }
});

// Feedback visual em tempo real
email.addEventListener('input', () => {
  email.setCustomValidity('');
  email.classList.toggle('valido', email.validity.valid);
  email.classList.toggle('invalido', !email.validity.valid && email.value);
});
input:valid {
  border-color: #28a745;
}

input:invalid {
  border-color: #dc3545;
}

input:focus:invalid {
  box-shadow: 0 0 0 3px rgba(220, 53, 69, 0.25);
}

Acessibilidade (WCAG 2.1)

<!-- Skip link para navegação por teclado -->
<a href="#conteudo" class="skip-link">Pular para conteúdo principal</a>

<!-- ARIA roles e labels -->
<nav aria-label="Navegação principal" role="navigation">
  <ul>
    <li><a href="/" aria-current="page">Home</a></li>
  </ul>
</nav>

<!-- aria-describedby para ajuda -->
<label for="cep">CEP:</label>
<input
  type="text"
  id="cep"
  name="cep"
  aria-describedby="cep-help"
  pattern="\d{5}-\d{3}"
>
<span id="cep-help" role="tooltip">Formato: 00000-000</span>

<!-- aria-label em botões icônicos -->
<button aria-label="Fechar modal">
  <span aria-hidden="true">&times;</span>
</button>

<!-- tabindex gerenciado -->
<div tabindex="0" role="button" class="card-clickavel">
  Conteúdo do card
</div>
.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  background: #000;
  color: #fff;
  padding: 8px;
  z-index: 100;
}

.skip-link:focus {
  top: 0;
}
// Gerenciamento de foco para modais
function abrirModal(modalId) {
  const modal = document.getElementById(modalId);
  modal.setAttribute('aria-hidden', 'false');
  modal.querySelector('[autofocus]')?.focus();

  // Trava foco dentro do modal
  modal.addEventListener('keydown', (e) => {
    if (e.key === 'Escape') fecharModal(modalId);
    if (e.key === 'Tab') travarFoco(modal, e);
  });
}

Lab: Formulário Acessível

Crie um formulário de cadastro com validação nativa, ARIA labels, feedback visual e skip link. Teste navegação por teclado (Tab, Enter).

# Teste com Lighthouse no Chrome
# DevTools > Lighthouse > Accessibility

# Leitor de tela (NVDA ou VoiceOver)
# Navegue com Tab e verifique os anúncios

Acessibilidade não é um recurso opcional — é direito do usuário e boa engenharia. Comece pela semântica correta.