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">×</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.