Example
Booking
Date and time inputs with bounds and step. The lib parses each value in the input's
own format — no hand-rolled date math. Validators stressed:
numeric, min, max, step.
<form id="booking-form" novalidate>
<div>
<label for="booking-date">Date</label>
<input id="booking-date" name="date" type="date"
data-validation="required;numeric" />
<ul class="error-list"></ul>
<small>Bounds (today and today + 30 days) are injected by the JS at runtime.</small>
</div>
<div>
<label for="booking-time">Time</label>
<input id="booking-time" name="time" type="time"
data-validation="required;numeric;min(09:00);max(18:00);step(1800)" />
<ul class="error-list"></ul>
<small>09:00–18:00, on the half-hour. <code>step</code> takes seconds for type=time.</small>
</div>
<div>
<label for="booking-party">Party size</label>
<input id="booking-party" name="party" type="number"
data-validation="required;numeric;min(1);max(8);step(1)" />
<ul class="error-list"></ul>
</div>
<button type="submit">Reserve</button>
</form> import { FormValidator } from '@form-validator-js/core';
import { required, numeric, min, max, step } from '@form-validator-js/validators';
const form = document.querySelector<HTMLFormElement>('#booking-form');
if (form) {
// Compute today + 30 days for the date bounds.
const today = new Date();
const todayIso = today.toISOString().slice(0, 10);
const in30 = new Date(today.getTime() + 30 * 86_400_000).toISOString().slice(0, 10);
// Inject computed bounds into the data-validation attributes.
const dateInput = form.querySelector<HTMLInputElement>('#booking-date');
if (dateInput) {
dateInput.dataset.validation = `required;numeric;min(${todayIso});max(${in30})`;
}
new FormValidator({
form,
validatorDeclarations: {
required: { ...required, errorMessage: 'Required' },
numeric: { ...numeric, errorMessage: 'Not a valid value' },
min: { ...min, errorMessage: 'Too early / too small' },
max: { ...max, errorMessage: 'Too late / too large' },
step: { ...step, errorMessage: 'Not on the allowed step' },
},
onErrorMessageListChanged(target, errors) {
if (target === form) return;
const list = (target as HTMLElement).parentElement?.querySelector('.error-list');
if (!list) return;
list.innerHTML = errors.map((m) => `<li>${m}</li>`).join('');
},
});
form.addEventListener('submit', (e) => {
e.preventDefault();
alert('Booked.');
});
}