Ein gut gemachtes Formular ist nicht nur „Felder + Senden“: Es muss den Benutzer leiten, Fehler verhindern und Daten auf klare Weise validieren. In diesem Leitfaden erstellen wir ein HTML-Formular mit clientseitiger Validierung in JavaScript unter Verwendung der Constraint Validation API, benutzerdefinierten Nachrichten und bewährten UX- und Zugänglichkeitsverfahren, mit Code zum Kopieren.
Clientseitige Validierung dient der Verbesserung der Benutzerfreundlichkeit: Sie meldet Fehler sofort, reduziert unnötige Übermittlungen und macht das Formular „benutzerfreundlicher“. Aber sie ist keine Sicherheitsmaßnahme: Jede Kontrolle muss trotzdem serverseitig wiederholt werden. Abgesehen davon ist eine gut gemachte Client-Validierung eines jener Details, die die Konversionsraten wirklich verändern (und „schmutzige“ Kontakte reduzieren).
In diesem Leitfaden zeigen wir, wie man ein modernes HTML-Formular mit clientseitiger Validierung in JavaScript erstellt, indem man die nativen Browser-Tools (Constraint Validation API) verwendet und personalisierte Nachrichten, Fehlerbehandlung, Zugänglichkeit und eine saubere UX hinzufügt.
Was bedeutet „clientseitige Validierung“
Clientseitige Validierung bedeutet, Daten zu überprüfen, bevor das Formular an den Server gesendet wird. Beispiele:
- E-Mail-Feld leer oder ungültig
- Passwort zu kurz
- Checkbox „Datenschutzbestimmungen akzeptieren“ nicht ausgewählt
- Telefonnummer mit falschem Format
Der beste Weg, dies zu tun, ist eine Kombination aus:
- HTML5-Validierung (required, type, minlength, pattern usw.)
- JavaScript zur Verwaltung von UI, benutzerdefinierten Nachrichten und zusätzlicher Logik
Goldene Regel: clientseitige UX, serverseitige Sicherheit
Denken Sie daran: Der Benutzer kann JS deaktivieren, HTML ändern oder Anfragen direkt über die API senden. Daher:
- Client-Validierung dient der UX und Datenqualität
- Server-Validierung dient der Sicherheit und Integrität
Komplettes Beispiel: Formular mit Validierung und benutzerdefinierten Nachrichten
Hier finden Sie ein fertiges Beispiel: Name, E-Mail, Telefon, Nachricht und Datenschutzeinwilligung. Wir verwenden:
- Constraint Validation API (checkValidity, reportValidity, validity)
- Fehlermeldungen für einzelne Felder
- CSS-Klassen für gültigen/ungültigen Status
- Barrierefreiheit mit aria-describedby und aria-live
<form id="contactForm" novalidate>
<div class="field">
<label for="name">Nome e cognome</label>
<input id="name" name="name" type="text" required minlength="2"
autocomplete="name" aria-describedby="nameError">
<p id="nameError" class="error" aria-live="polite"></p>
</div>
<div class="field">
<label for="email">Email</label>
<input id="email" name="email" type="email" required
autocomplete="email" aria-describedby="emailError">
<p id="emailError" class="error" aria-live="polite"></p>
</div>
<div class="field">
<label for="phone">Telefono (opzionale)</label>
<input id="phone" name="phone" type="tel"
inputmode="tel"
pattern="^+?[0-9s-]{7,20}$"
placeholder="+39 348 123 4567"
autocomplete="tel" aria-describedby="phoneHelp phoneError">
<small id="phoneHelp" class="help">Formato ammesso: numeri, spazi e trattini.</small>
<p id="phoneError" class="error" aria-live="polite"></p>
</div>
<div class="field">
<label for="message">Messaggio</label>
<textarea id="message" name="message" required minlength="10" rows="5"
aria-describedby="messageError"></textarea>
<p id="messageError" class="error" aria-live="polite"></p>
</div>
<div class="field">
<label class="checkbox">
<input id="privacy" name="privacy" type="checkbox" required aria-describedby="privacyError">
Ho letto e accetto l’informativa privacy
</label>
<p id="privacyError" class="error" aria-live="polite"></p>
</div>
<button type="submit">Invia</button>
<p id="formStatus" class="status" aria-live="polite"></p>
</form>
Minimale Stile (optional), um die Zustände klar darzustellen:
.field { margin-bottom: 14px; }
label { display:block; margin-bottom: 6px; font-weight: 600; }
input, textarea { width: 100%; padding: 10px; border: 1px solid #ccc; border-radius: 8px; }
input.is-invalid, textarea.is-invalid { border-color: #c0392b; }
input.is-valid, textarea.is-valid { border-color: #27ae60; }
.error { margin: 6px 0 0; color: #c0392b; font-size: 0.95rem; }
.help { display:block; margin-top: 6px; color:#666; font-size: 0.9rem; }
.status { margin-top: 12px; }
Und jetzt der JavaScript-Teil: Validierung beim Absenden + „Live“-Validierung während der Eingabe.
(() => {
const form = document.getElementById('contactForm');
const statusEl = document.getElementById('formStatus');
// Mappa campo -> elemento errori
const errorMap = new Map([
['name', document.getElementById('nameError')],
['email', document.getElementById('emailError')],
['phone', document.getElementById('phoneError')],
['message', document.getElementById('messageError')],
['privacy', document.getElementById('privacyError')],
]);
const getErrorMessage = (input) => {
const v = input.validity;
if (v.valueMissing) {
// Messaggi specifici per campo
if (input.name === 'privacy') return 'Devi accettare l’informativa privacy per proseguire.';
return 'Questo campo è obbligatorio.';
}
if (v.typeMismatch) {
if (input.type === 'email') return 'Inserisci un indirizzo email valido.';
return 'Formato non valido.';
}
if (v.tooShort) {
return `Inserisci almeno ${input.minLength} caratteri.`;
}
if (v.patternMismatch) {
if (input.name === 'phone') return 'Inserisci un numero valido (numeri, spazi e trattini).';
return 'Formato non valido.';
}
if (v.badInput) return 'Valore non valido.';
return '';
};
const setFieldState = (input, isValid, message = '') => {
const errorEl = errorMap.get(input.name);
if (errorEl) errorEl.textContent = message;
input.classList.toggle('is-invalid', !isValid);
input.classList.toggle('is-valid', isValid);
// Per accessibilità: aria-invalid quando non valido
input.setAttribute('aria-invalid', String(!isValid));
};
const validateField = (input) => {
// telefono opzionale: se vuoto, consideralo valido
if (input.name === 'phone' && input.value.trim() === '') {
setFieldState(input, true, '');
return true;
}
const ok = input.checkValidity();
const msg = ok ? '' : getErrorMessage(input);
setFieldState(input, ok, msg);
return ok;
};
const focusFirstInvalid = () => {
const firstInvalid = form.querySelector('.is-invalid');
if (firstInvalid) firstInvalid.focus({ preventScroll: false });
};
// Validazione live: al blur e all'input
form.addEventListener('blur', (e) => {
const target = e.target;
if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement) {
validateField(target);
}
}, true);
// Debounce semplice per non validare a ogni tasto in modo aggressivo
let t = null;
form.addEventListener('input', (e) => {
const target = e.target;
if (!(target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement)) return;
clearTimeout(t);
t = setTimeout(() => validateField(target), 200);
});
form.addEventListener('submit', async (e) => {
e.preventDefault();
statusEl.textContent = '';
const inputs = Array.from(form.querySelectorAll('input, textarea'));
const allOk = inputs.every(validateField);
if (!allOk) {
statusEl.textContent = 'Controlla i campi evidenziati.';
focusFirstInvalid();
return;
}
// Qui invieresti i dati al server (fetch/AJAX) oppure lasci fare al form
// Esempio placeholder:
statusEl.textContent = 'Invio in corso...';
try {
// Simulazione invio
await new Promise((r) => setTimeout(r, 400));
statusEl.textContent = 'Messaggio inviato correttamente.';
form.reset();
// Pulisci stati visivi dopo reset
inputs.forEach((i) => {
i.classList.remove('is-valid', 'is-invalid');
i.removeAttribute('aria-invalid');
const err = errorMap.get(i.name);
if (err) err.textContent = '';
});
} catch (err) {
statusEl.textContent = 'Errore durante l’invio. Riprova.';
}
});
})();
Warum die Constraint Validation API verwenden?
Viele erfinden das Rad mit Regex überall und manuellen Kontrollen neu. Tatsächlich bieten moderne Browser ein robustes, bereits fertiges System:
checkValidity()prüft die Gültigkeit des Feldes, ohne Browser-Popups anzuzeigenreportValidity()kann die nativen Nachrichten anzeigen (nützlich in einfachen Fällen)validityzeigt den detaillierten Status an (valueMissing, tooShort, typeMismatch, patternMismatch…)
So konzentrieren Sie sich auf die UX (Nachrichten, Hervorhebung, Barrierefreiheit), ohne unnötige Logiken zu duplizieren.
„Sanfte“ Validierung: Wann der Fehler angezeigt werden soll
Ein zu früh angezeigter Fehler kann störend sein. Praktische Richtlinien:
- Fehler anzeigen beim Absenden (immer)
- Fehler anzeigen beim Blur (wenn der Benutzer das Feld verlässt)
- „live“ während der Eingabe nur mit Debounce und nur validieren, wenn das Feld bereits berührt wurde (fortschrittlicherer Ansatz)
Im Beispiel validieren wir beim Absenden alles; während der Eingabe validieren wir beim Blur und mit einem leichten Debounce.
Barrierefreiheit: Keine Option
Zwei Punkte machen den Unterschied:
- Verknüpfen Sie den Fehlertext mit dem Feld mit
aria-describedby - Aktualisieren Sie den Status mit
aria-invalidbei Bedarf
Zusätzlich ermöglicht die Verwendung von aria-live="polite" auf dem Fehlertext Screenreadern, die Änderung zu kommunizieren.
Schnelle FAQs
Muss ich novalidate im Formular verwenden?
Wenn Sie Nachrichten und UI selbst verwalten möchten, ja: novalidate deaktiviert die nativen Browser-Popups und ermöglicht Ihnen eine konsistente UX. Wenn die Standard-HTML5-Validierung ausreicht, können Sie es auch weglassen.
Ist der Regex für die Telefonnummer obligatorisch?
Nein. Telefonnummern sind komplex (verschiedene Formate). Besser ist eine permissive clientseitige Validierung und serverseitige Normalisierung, oder dedizierte Bibliotheken, wenn hohe Präzision erforderlich ist.
Kann ich mit fetch senden, ohne die Seite neu zu laden?
Ja. Im Submit-Block finden Sie bereits eine Stelle, an der Sie fetch() einfügen können. Denken Sie daran: immer serverseitige Validierung, Fehlerbehandlung und klare Nachrichten clientseitig.
Fazit
Ein Formular mit clientseitiger Validierung in JavaScript muss nicht kompliziert sein: HTML5 liefert bereits solide Regeln, JavaScript ermöglicht es Ihnen, diese klarer, konsistenter und zugänglicher zu gestalten. Wenn Sie nützliche Nachrichten erstellen, Fehler richtig hervorheben und die Barrierefreiheit nicht vergessen, erhalten Sie schnellere Formulare, weniger Frustration und bessere Datenqualität.
Pubblicato in HTML & CSS, JavaScript
Hinterlasse jetzt einen Kommentar