HTML5 Form Validation
Why no one uses it, and how you can!
TJ VanToll | @tjvantoll
- My name is TJ VanToll I work for Telerik (poll room)
- We're a software development company, and we specialize in UI tools. Kendo UI?
- So I work on Kendo UI
- I'm also a member of the jQuery UI team
Traditional form validation is hard
document.getElementById( "myForm" )
.addEventListener( "submit", function( event ) {
if ( document.getElementById( "myInput" ).value == "" ) {
event.preventDefault();
// Show some questionably UX and a11y
// friendly error message.
}
});
});
HTML5 form validation is totally cool
<form>
<input required>
<button>Submit</button>
</form>
Submit
- I find most conference talks are about things you can't use or things that aren't applicable.
- Form validation is practical
- Everyone does it
- Poll the room
Native Form Validation: A quick history
“No one uses HTML5 form validation”
-Me
Problems:
Browser support is weird
setCustomValidity() is an odd API
Customizing error messages is hard
Aggregating error messages is hard
The :invalid pseudo-class is tricky to use
You cannot style the bubbles
Problem #1: Browser support is weird
The curious case of Benjamin Button constraint validation on Safari, iOS Safari, and the Android browser.
Safari/iOS Safari/Android Browser let this submit empty
<form>
<input required>
<button>Submit</button>
</form>
Submit
Two scenarios to account for
- Old IE
- Safari / iOS Safari / Android Browser
Client-side validation is no substitute for server-side validation
curl --data "param1=DELETE * FROM *" http://foo.com/bar.do
Your server is your fallback
Example
Problem #2: setCustomValidity() is an odd API
Example 1
Problem #3: Customizing error messages is hard
Customizing messages
<form>
<input required type="email" id="baz">
<button>Go</button>
</form>
<script>
var baz = document.querySelector( "#baz" );
function setErrorMessage() {
if ( baz.validity.valueMissing ) {
baz.setCustomValidity( "Email is required" );
} else if ( baz.validity.typeMismatch ) {
baz.setCustomValidity( "Please provide a valid email address" );
} else {
baz.setCustomValidity( "" );
}
};
setErrorMessage();
baz.addEventListener( "change", setErrorMessage );
</script>
Go
x-moz-errormessage
<form>
<input required x-moz-errormessage="INVALID!">
<button>Go</button>
</form>
Go
W3C Bug #10923: Add an attribute to override UI's validation message
title attribute
<form>
<input pattern="[0-9]{5}" title="Enter 5 numbers">
<button>Go</button>
</form>
Go
Problem #4: Aggregating error messages is hard
There is no way to determine when the user attempted to submit a form.
<form id="foo">
<input required>
<button>Go</button>
<script>
document.querySelector( "#foo" )
.addEventListener( "submit", function() {
alert( "hi!" );
});
</script>
</form>
Go
Aggregating Messages
Demo
Coming soon: invalid event on <form> elements!
Problem #5: The :invalid pseudo-class is tricky to use
:invalid applies immediately!
<form>
<input type="text" id="foo" required>
</form>
<style>
#foo:invalid { background: red; }
</style>
:moz-ui-invalid
Only match after interaction or attempted submission (full algorithm).
<form>
<input type="text" id="bar" required>
<button>Go</button>
</form>
<style>
#bar:-moz-ui-invalid { background: red; }
</style>
Go
CSS Selectors Level 4 Spec
Only use :invalid after interaction
Demo
Problem #6: You cannot style the bubbles
Old WebKit Hooks
WebKit used to have these pseudo-elements.
- ::-webkit-validation-bubble
- ::-webkit-validation-bubble-arrow
- ::-webkit-validation-bubble-arrow-clipper
- ::-webkit-validation-bubble-heading
- ::-webkit-validation-bubble-message
- ::-webkit-validation-bubble-text-block
You used to be able to do this
Styling the Bubbles
Chrome 28 removed the pseudo-elements for styling form validation messages.
Turning the bubbles off
<form>
<input required id="field-x">
<button>Go</button>
</form>
<script>
document.getElementById( "field-x" )
.addEventListener( "invalid", function( event ) {
event.preventDefault();
});
</script>
Go
Turning the bubbles off (for a whole form)
<form id="form-x">
<input required>
<button>Go</button>
</form>
<script>
document.getElementById( "form-x" )
.addEventListener( "invalid", function( event ) {
event.preventDefault();
}, true );
</script>
Go
Building your own bubbles
Demo
Problems:
Browser support is weird
setCustomValidity() is an odd API
Customizing error messages is hard
Aggregating error messages is hard
The :invalid pseudo-class is tricky to use
You cannot style the bubbles
Production usage: your options
Server-side fallback only
Polyfill
Use a library based on HTML5
Option #1: Server-side fallback only
Demo
Option #3: Use a library based on HTML5
Production usage: your options
Server-side fallback only
Polyfill
Use a library based on HTML5