JSFiddle - React, Tailwind, and code Playground
by mcsf
HTML
<p><strong>
Focus the first field, then keep trying to submit by pressing <kbd>ENTER</kbd>.<br>Watch as the browser guides you through the form to fix all the inputs.
</strong></p>
<form
onsubmit="doSubmit(event, this)"
onchange="validate(this)"
>
Name (not required):
<input>
<br>
Name (required):
<input required>
<br>
Name (at least three characters):
<input required minlength="3">
<br>
Full name (needs at least two separate words):
<input required pattern="\w+( \w+)+">
<br>
Full name (uses custom message to inform user):
<input required pattern="\w+( \w+)+" onchange="validateFullName(event)">
<br>
Email (required, needs valid email address):
<input required type="email">
<br>
Email (with custom rules):
<input required type="email" x-validate="NO_SPAIN_TLD ARTURITOS_ONLY">
<br>
<input type="submit">
</form>
CSS
body {
background-color: #eee;
}
JavaScript
// Ad-hoc validation for the `fullName` input
function validateFullName({target}) {
target.setCustomValidity(
target.validity.patternMismatch
? 'Your full name should include at least a first name and a surname.'
: ''
);
}
// Micro-framework using the `x-validate` custom attribute
const VALIDATIONS = {
NO_SPAIN_TLD: [input => !input.value.match(/\.es$/), 'No Spain, plz!'],
ARTURITOS_ONLY: [input => input.value.match(/^arturito/), 'Only Arturitos!'],
};
function doSubmit(event, form) {
event.preventDefault();
alert('Submitted');
}
function validate(form) {
form.querySelectorAll('[x-validate]').forEach(input => {
const validations = input.getAttribute('x-validate').split(' ');
for (const v of validations) {
if (VALIDATIONS[v]) {
const [predicate, message] = VALIDATIONS[v];
if (! predicate(input)) {
input.setCustomValidity(message);
break;
}
input.setCustomValidity('');
}
}
});
}