Signatur
Beschreibung
Mit setCustomValidity() hängst du eigene Prüfregeln an ein <select>-Element. Die eingebauten HTML-Attribute wie required reichen dafür oft nicht aus. Solange eine nicht leere Nachricht gesetzt ist, gilt das Element als ungültig: validity.customError ist true, validity.valid ist false, und die CSS-Pseudoklasse :invalid greift. Außerdem wird das Formular beim Absenden blockiert, solange es nicht mit novalidate ausgezeichnet ist.
Typische Einsätze sind Abhängigkeiten zwischen Feldern, zum Beispiel „Expressversand ist für dieses Land nicht möglich“. Auch Platzhalter-Optionen wie „Bitte wählen…“ mit einem Wert ungleich leer gehören dazu, ebenso Prüfungen, die erst nach einer Serverantwort feststehen. Der Browser zeigt die Nachricht an, sobald reportValidity() aufgerufen oder das Formular abgeschickt wird.
Wichtig: Der eigene Fehler bleibt bestehen, bis du ihn ausdrücklich mit setCustomValidity("") zurücksetzt. Deshalb gehört die Prüfung in einen change- oder input-Handler. Der Handler setzt bei gültiger Auswahl immer den leeren String. Sonst lässt sich das Formular nie mehr absenden.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $message Pflicht | string | Die Fehlermeldung, die dem Nutzer angezeigt wird. Ein leerer String "" entfernt den eigenen Fehler und macht das Element (bezogen auf diese Regel) wieder gültig. Andere Werte werden in einen String umgewandelt. |
Rückgabewert
validationMessage, validity.customError und checkValidity().Beispiele
Platzhalter-Option als ungültig markieren
// <select id="land"><option value="none">Bitte wählen…</option><option value="de">Deutschland</option></select>
const land = document.querySelector('#land');
const pruefen = () => {
land.setCustomValidity(
land.value === 'none' ? 'Bitte wählen Sie ein Land aus.' : ''
);
};
land.addEventListener('change', pruefen);
pruefen(); // Anfangszustand prüfen
console.log(land.validity.customError, land.validationMessage);
Abhängige Felder prüfen (Land + Versandart)
const land = document.querySelector('#land');
const versand = document.querySelector('#versand');
const validiereVersand = () => {
if (versand.value === 'express' && land.value !== 'de') {
versand.setCustomValidity('Expressversand ist nur innerhalb Deutschlands möglich.');
} else {
versand.setCustomValidity(''); // Fehler unbedingt zurücksetzen
}
};
[land, versand].forEach((el) => el.addEventListener('change', validiereVersand));
document.querySelector('form').addEventListener('submit', (e) => {
validiereVersand();
if (!e.target.reportValidity()) e.preventDefault();
});
Serverseitige Prüfung per fetch
const tarif = document.querySelector('#tarif');
tarif.addEventListener('change', async () => {
tarif.setCustomValidity(''); // alten Fehler entfernen
const res = await fetch(`/api/tarif-verfuegbar?id=${encodeURIComponent(tarif.value)}`);
const { verfuegbar } = await res.json();
if (!verfuegbar) {
tarif.setCustomValidity('Dieser Tarif ist derzeit ausgebucht.');
tarif.reportValidity(); // Meldung sofort anzeigen
}
});
// Wichtig · Fallstricke
- Häufigster Fehler: Die Nachricht wird gesetzt, aber nie mit
""zurückgesetzt. Das Element bleibt dann dauerhaft ungültig, und das Formular lässt sich nicht mehr absenden. - Das bloße Setzen zeigt noch keine Meldung an. Erst
reportValidity()oder ein Absendeversuch blendet die Blase ein. - Aussehen und Anzeigedauer der Browser-Blase unterscheiden sich je nach Browser und lassen sich nicht gestalten. Für eigene Oberflächen liest du
validationMessageaus und zeigst sie selbst an, z. B. nach Unterdrückung über dasinvalid-Event mitpreventDefault(). - Ist das Element
disabled, wird es bei der Validierung übersprungen, auch wenn ein eigener Fehler gesetzt ist. - Die Prüfung im Client ersetzt keine Prüfung auf dem Server. Sie lässt sich leicht umgehen.
- Die Methode wird von allen modernen Browsern unterstützt, auch von älteren Versionen.