Signatur
Beschreibung
Die Eigenschaft validity von ElementInternals liefert ein ValidityState-Objekt für ein formularassoziiertes Custom Element, also eine Klasse mit static formAssociated = true. Das Objekt enthält dieselben booleschen Merkmale wie bei nativen Formularfeldern: valueMissing, typeMismatch, patternMismatch, tooLong, tooShort, rangeUnderflow, rangeOverflow, stepMismatch, badInput, customError und die Zusammenfassung valid.
Die Eigenschaft selbst ist nur lesbar. Den Zustand setzt du ausschließlich über ElementInternals.setValidity(flags, message, anchor). Wenn du setValidity({}) ohne Merkmale aufrufst, gilt das Element wieder als gültig. Das zurückgegebene Objekt ist „live“ und spiegelt jederzeit den aktuellen Zustand wider.
Typische Einsatzfälle sind Eingabekomponenten wie Datumswähler, Bewertungssterne oder Tag-Eingaben. Sie sollen sich mit form.checkValidity(), :invalid-CSS und der Formularübermittlung genauso verhalten wie ein natives <input>. Oft stellt man validity zusätzlich als öffentlichen Getter der Komponente bereit, damit sie dieselbe Schnittstelle wie native Felder bietet.
Rückgabewert
valid ist true, wenn kein anderes Merkmal gesetzt ist.Beispiele
Pflichtfeld-Komponente mit Validierung
class RatingInput extends HTMLElement {
static formAssociated = true;
#internals = this.attachInternals();
#value = 0;
connectedCallback() {
this.#update();
}
set value(v) {
this.#value = Number(v);
this.#internals.setFormValue(String(this.#value));
this.#update();
}
#update() {
if (this.hasAttribute('required') && this.#value === 0) {
this.#internals.setValidity({ valueMissing: true }, 'Bitte eine Bewertung wählen.');
} else {
this.#internals.setValidity({}); // gültig
}
}
// native API nachbilden
get validity() { return this.#internals.validity; }
get validationMessage() { return this.#internals.validationMessage; }
}
customElements.define('rating-input', RatingInput);
const el = document.createElement('rating-input');
el.setAttribute('required', '');
document.body.append(el);
console.log(el.validity.valid, el.validity.valueMissing);
el.value = 4;
console.log(el.validity.valid);
Fehlerursache auswerten
class CodeInput extends HTMLElement {
static formAssociated = true;
internals = this.attachInternals();
check(text) {
if (text.length < 4) {
this.internals.setValidity({ tooShort: true }, 'Mindestens 4 Zeichen.');
} else if (!/^[A-Z0-9]+$/.test(text)) {
this.internals.setValidity({ patternMismatch: true }, 'Nur Großbuchstaben und Ziffern.');
} else {
this.internals.setValidity({});
}
const v = this.internals.validity;
return Object.fromEntries(
['valid', 'tooShort', 'patternMismatch'].map((k) => [k, v[k]])
);
}
}
customElements.define('code-input', CodeInput);
const c = document.createElement('code-input');
console.log(c.check('ab'));
console.log(c.check('abcd'));
console.log(c.check('AB12'));
Zusammenspiel mit dem Formular
const form = document.createElement('form');
const rating = document.createElement('rating-input');
rating.setAttribute('required', '');
form.append(rating);
document.body.append(form);
form.addEventListener('submit', (e) => {
if (!rating.validity.valid) {
e.preventDefault();
console.warn(rating.validationMessage);
}
});
console.log(form.checkValidity()); // berücksichtigt das Custom Element
// Wichtig · Fallstricke
- Ist das Element nicht formularassoziiert (kein
static formAssociated = true), löst der Zugriff aufvalidityeineNotSupportedError-DOMExceptionaus. - Die Eigenschaft ist schreibgeschützt. Zuweisungen wie
internals.validity.valid = truehaben keine Wirkung. Ändern lässt sich der Zustand nur mitsetValidity(). - Setzt du in
setValidity()ein Fehlermerkmal, musst du auch einen nicht-leerenmessage-String übergeben. Sonst wird einTypeErrorausgelöst. - Der Browser prüft Attribute wie
requiredoderminlengthan Custom Elements nicht automatisch. Diese Prüfung musst du selbst implementieren. - Elemente mit
disabled,readonlyoder innerhalb eines deaktivierten<fieldset>werden von der Constraint-Validierung ausgenommen.validitykann dann trotzdem Fehler melden, obwohl das Formular abgesendet wird. - Browser-Unterstützung: Chrome/Edge 77+, Firefox 98+, Safari 16.4+. In älteren Safari-Versionen ist dafür ein Polyfill wie
element-internals-polyfillnötig.