Используй required, pattern, inputmode и Constraint Validation API, чтобы получить надёжные формы без единой внешней библиотеки.
Открыть этот урок в KodokonВ браузере встроен полноценный движок валидации, который многие команды по привычке заново пишут на JavaScript. Из чего он состоит: required (обязательное поле), типы (email, url, date), проверяющие формат, minlength/maxlength, min/max/step для числовых значений и pattern, принимающий регулярное выражение. Важнейшая деталь: pattern неявно привязан к границам - совпасть должно всё значение целиком, как если бы регулярное выражение было обёрнуто в ^ и $. Добавляй autocomplete со стандартизированными значениями (postal-code, email, tel): это одновременно UX и доступность.
<label for="zip">Postal code</label>
<input id="zip" name="zip" type="text"
required pattern="[0-9]{5}"
inputmode="numeric"
autocomplete="postal-code">Атрибут inputmode часто понимают неправильно: он не проверяет ничего. Он лишь сообщает мобильной системе, какую виртуальную клавиатуру показать (numeric, tel, email, decimal, search). Именно поэтому связка type="text" + inputmode="numeric" + pattern - рекомендуемый приём для числовых кодов: ты получаешь нужную клавиатуру, не наследуя поведение type="number".
input:user-invalid {
border: 2px solid #b3261e;
}
input:user-valid {
border: 2px solid #1b5e20;
}Со стороны CSS предпочитай :user-invalid, а не :invalid: последний применяется сразу при загрузке страницы и красит красным поля, которых пользователь ещё даже не касался. Со стороны JavaScript инструментарий дополняет Constraint Validation API: checkValidity() запускает проверку, объект validity показывает точную причину (patternMismatch, valueMissing, tooShort), а setCustomValidity() позволяет заменить типовые сообщения браузера своими.
const zip = document.querySelector("#zip");
zip.addEventListener("input", () => {
if (zip.validity.patternMismatch) {
zip.setCustomValidity("Enter 5 digits.");
} else {
zip.setCustomValidity("");
}
});