Key Takeaways
- HTML5 introduced new input types and attributes that allow browsers to perform client-side validation with minimal JavaScript, improving user experience with faster, instant feedback. However, server-side validation is still necessary.
- HTML5 form validation can be achieved by using the ‘required’ attribute for necessary fields, the ‘pattern’ attribute for specific data formats, and the ‘type’ attribute for email, URL, and number validation. The ‘min’ and ‘max’ attributes can also be used to restrict numerical input.
- CSS3 pseudo-classes can be used to provide visual cues for form fields, indicating which fields are required, optional, or contain valid or invalid data. This can enhance user experience and guide users in filling out forms correctly.
- HTML5 form validation is supported by all the latest desktop browsers and most mobile browsers, but only partially supported in Safari, and not supported at all on iOS Safari or the default Android browser. In such cases, JavaScript can be used for client-side validation.
A few months ago Sandeep introduced us to the HTML Constraint API, showing how we can use the new HTML5 input types and attributes to validate our forms in the browser with minimal JavaScript. Today I’m going to walk you through validating a simple booking form by using the Constraint API, and keep an eye on how you can make sure your forms stay accessible too.
To recap—or in case you haven’t read Sandeep’s article—with the dawn of HTML5, a raft of new input types and attributes were added to <input>
tags that allow the browsers themselves to perform the client-side validation for us: no JavaScript required. To start using the new input types and attributes, you don’t really need to do anything other than start using the new input types and attributes.
Strictly speaking, you should make sure you’re using the HTML5 DOCTYPE, otherwise you’ll run into HTML validation errors. But the great thing about them is that they all degrade gracefully. So if an older browser doesn’t support them, the fact that they’re in the HTML won’t ‘break’ anything, they’ll just be rendered as an <input type=”text”>
.
NB While client-side form validation is great for enhancing user experience—fast, instant feedback to the user without making a round trip to the server—you will still need to validate any data submitted on the server, too.
Let’s walk through an example of how we can validate a form using only the browser’s built in validation. Take this simple booking form:
<form action="" method="post">
<fieldset>
<legend>Booking Details</legend>
<div>
<label for="name">Name (required):</label>
<input type="text" id="name" name="name" value="" aria-describedby="name-format">
<span id="name-format" class="help">Format: firstname lastname</span>
</div>
<div>
<label for="email">Email (required):</label>
<input type="text" id="email" name="email" value="">
</div>
<div>
<label>Website:</label>
<input type="text" id="website" name="website" value="">
</div>
<div>
<label for="numTickets"><abbr title="Number">No.</abbr> of Tickets (required):</label>
<input type="text" id="numTickets" name="numTickets" value="">
</div>
<div class="submit">
<input type="submit" value="Submit">
</div>
</fieldset>
</form>
https://jsfiddle.net/ianoxley/aZ9r8/1/
Note that each input field has an associated <label>
tag. The for
attribute for the label tag matches up with the id attribute of the associated input tag. This keeps our HTML semantic, with the labels helping to give meaning to the input controls. It also means that if you click the label, the associated input tag receives the focus.
They also help with accessibility, as the text in the label will be read out to screen reader users: it can therefore be useful to indicate required fields by adding ‘required’ to the label text, as I’ve done above.
I’m also using the WAI ARIA aria-describedby
attribute, which helps inform users of the format in which they should enter their name.
<label for="name">Name (required):</label>
<input type="text" id="name" name="name" value="" aria-describedby="name-format">
<span id="name-format" class="help">Format: firstname lastname</span>
This is shown when the input field it describes receives focus, providing context-sensitive help:
.help {
display:none;
font-size:90%;
}
input:focus + .help {
display:inline-block;
}
To validate this form we’ll need to:
- Make sure the required fields have been completed
- Make sure what’s entered for ‘Name’ is name-like
- Make sure the email address looks like an email address
- Check that if a website URL has been provided, it looks like a URL
- Make sure a number has been entered in ‘Number of tickets’
Required fields
Validating required fields is as easy as adding the required
attribute to each <input>
tag that must be completed, namely Name, Email, and Number of Tickets. For example, Name now looks like this:
<div>
<label for="name">Name:</label>
<input id="name" name="name" value="" aria-describedby="name-format" required>
<span id="name-format" class="help">Format: firstname lastname</span>
</div>
If we try to submit this form now without completing any of the required fields, the browser will notify us:
Did you notice how we no longer have ‘required’ in the required fields <label>
tags anymore? This is because most screen readers will pick up the required
attribute now, so if we leave ‘required’ in the label tag screen reader users will have ‘required’ read to them twice, which they could find rather annoying.
A word of warning though: not all browsers implement the required
attribute accessibly, so it might not be picked up correctly in certain browser / screen reader combinations. As such, current best practice recommends supplementing the required attribute with the aria-required=”true” attribute:
<input id="name" name="name" value="" aria-describedby="name-format" required aria-required=”true”/>
Validating the data
Now that our users get prompted to complete required fields, we need to make sure that the data they submit is in the format we require.
We’ll want the ‘Name’ field to be submitted in the format ‘Firstname Lastname’, and to only contain letters and a space (NB in real world scenarios, you might need to take account of other locales – this example has been kept simple deliberately). We can achieve this by adding a pattern attribute to the ‘Name’ field, setting it’s value to the regular expression we want the data to be compared against:
<input id="name" name="name" value="" aria-describedby="name-format" required aria-required=”true” pattern="[A-Za-z-0-9]+\s[A-Za-z-'0-9]+">
When using the pattern attribute, the ^
and $
for the start and end of the regular expression are implied and don’t need to be included.
You can help the user by including a title attribute that tells them the format you require:
<input id="name" name="name" value="" aria-describedby="name-format" required aria-required=”true” pattern="[A-Za-z-0-9]+\s[A-Za-z-'0-9]+" title="firstname lastname">
The text in the title attribute is then appended to the built-in validation message:
Note that some screen reader / browser combinations might lead to the title attribute being read out in addition to the aria-describedby text, so watch out for this e.g. I found that using NVDA with IE10 caused the title attribute and the aria-describedby element’s text to be read out, but using NVDA with Chrome and Firefox didn’t exhibit this behaviour. Only the aria-describedby text was read. Later on we’ll revisit this and show you one solution using CSS3.
Validating emails, URLs, and numbers
To make sure our user enters the right data in the email, website, and number of tickets fields, we can use some of the new input types added in HTML5:
<input type="email" id="email" name="email" required>
…
<input type="url" id="url" name="url">
…
<input type="number" id="numTickets" name="numTickets" required>
By specifying the appropriate type, our browser will validate the data for us and make sure we’ve got an email address in the email field, a URL in the website field, and a number in the number of tickets field.
Note too that the type
attribute is no longer a required attribute itself. If you don’t specify it the input
tag will implicitly be of type="text"
.
Suppose we wanted to restrict the number of tickets each person could buy? We can do this by using the max
and min
attributes:
<input type="number" min="1" max="4" id="numTickets" name="numTickets">
If the user enters anything less than 1 or greater than 4, they’ll be prompted to enter a number in the permitted range.
Using CSS to highlight required fields and invalid data
In tandem with the new input types and attributes provided by HTML5, CSS3 gives us some new pseudo-classes we can use to provide visual clues to the user as to which form fields are required, which are optional, and which contain validation errors.
Required fields can use the :required
pseudo-class:
input:required {
background:hsl(180, 50%, 90%);
border:1px solid #999;
}
Optional fields can use the :optional
pseudo-class:
input:optional {
background:hsl(300, 50%, 90%);
border:1px dotted hsl(180, 50%, 90%);
}
The success or failure of form validation can be signified to the user through the use of the :valid
, :invalid
, :in-range
, and :out-of-range
pseudo-classes:
input:valid,
input:in-range {
background:hsl(120, 50%, 90%);
border-color:hsl(120, 50%, 50%);
}
input:invalid,
input:out-of-range {
border-color:hsl(0, 50%, 50%);
background:hsl(0, 50%, 90%);
}
Remember earlier when I mentioned certain screen reader / browser combinations can lead to the title attribute being read aloud in addition to the aria-describedby
element’s text? Well, one way around this is to remove the title attribute from the input element, and make use of the CSS3 :invalid
pseudo class to show the aria-describedby
text:
input:focus + .help,
input:invalid + .help {
display:inline-block;
}
Now, in addition to showing the help text when the input field receives focus, we’ll also show the help text when the input field’s value is invalid.
After making all these changes our HTML now looks like this:
<form action="" method="post">
<fieldset>
<legend>Booking Details</legend>
<div>
<label for="name">Name:</label>
<input id="name" name="name" value="" required pattern="[A-Za-z-0-9]+\s[A-Za-z-'0-9]+" aria-required="true" aria-describedby="name-format">
<span id="name-format" class="help">Format: firstname lastname</span>
</div>
<div>
<label for="email">Email:</label>
<input type="email" id="email" name="email" value="" required aria-required="true">
</div>
<div>
<label for="website">Website:</label>
<input type="url" id="website" name="website" value="">
</div>
<div>
<label for="numTickets"><abbr title="Number">No.</abbr> of Tickets:</label>
<input type="number" id="numTickets" name="numTickets" value="" required aria-required="true" min="1" max="4">
</div>
<div class="submit">
<input type="submit" value="Submit">
</div>
</fieldset>
</form>
https://jsfiddle.net/ianoxley/VY8KU/
Disabling browser-based validation
You can disable the built-in browser validation by adding a novalidate
attribute to your <form>
tag:
<form novalidate>
…
</form>
https://jsfiddle.net/ianoxley/9C2JD/
Cross-browser?
The good news is that HTML form validation is supported by all the latest desktop browsers, and most mobile browsers. The bad news is that it is only partially supported in Safari, and isn’t supported at all on iOS Safari, or the default Android browser. If you need to support older versions of IE prior to IE10 you won’t find any of those support form validation either.
So, what can you do if you have to support browsers that don’t have support for form validation yet?
One option is to not do anything and rely on your server-side validation only. This would require no extra work on your part, but would the UX for those using unsupported browsers be satisfactory?
Another option would be to continue to use solely JavaScript for your client-side validation, and not add any of the new features discussed above.
A third approach is to use JavaScript to detect whether the browser supports form validation, use it if it does, and fall back to JavaScript-based validation if it doesn’t. Libraries such as Modernizr can help with HTML5 feature detection, but you can always write your own code if you don’t want to include another JavaScript library:
// Without Moderizr
var inputElem = document.createElement('input');
if (!('required' in inputElem)) {
// JavaScript form validation
}
...
// With Modernizr
if (!Modernizr.input.required) {
// JavaScript form validation
}
Conclusion
In this article we’ve walked through applying HTML5 form validation to a booking form client-side without using any JavaScript, and pointed out some accessibility issues to be wary of. We then looked at how new CSS3 pseudo-classes can be used to give visual cues to the user as to which fields are required and options, and which contain valid or invalid data. Finally we covered how to disable HTML form validation, and detect whether form validation was available or not in case we have to support browsers that are yet to support this feature.
Let me know what you think of all this in the comments. Teach yourself HTML5 in a single weekend. SitePoint’s latest HTML5 guide, Jump Start HTML5, is free to read with a Learnable trial.Frequently Asked Questions (FAQs) about HTML5 Form Validation
What is the importance of HTML5 form validation?
HTML5 form validation is a crucial aspect of web development. It ensures that the data entered by users into a web form meets certain criteria before it’s sent to the server. This not only improves the user experience by providing immediate feedback but also enhances the security of your website by preventing malicious or incorrect data from being submitted.
How does HTML5 form validation differ from JavaScript form validation?
HTML5 form validation is built into the browser, making it faster and more efficient than JavaScript form validation. It doesn’t require any additional scripting, which can reduce the load time of your web pages. However, JavaScript form validation offers more flexibility and customization options, allowing you to create complex validation rules that may not be possible with HTML5 alone.
Can I customize the error messages in HTML5 form validation?
Yes, you can customize the error messages in HTML5 form validation using the setCustomValidity() method. This method allows you to set a custom message that will be displayed when the validation constraints are not met. You can use this feature to provide more specific and helpful feedback to your users.
How can I use regular expressions in HTML5 form validation?
Regular expressions can be used in HTML5 form validation to create complex validation rules. You can use the pattern attribute in your input elements to specify a regular expression. The input data will be validated against this pattern, and the form will not be submitted unless the data matches the pattern.
What are the limitations of HTML5 form validation?
While HTML5 form validation offers many benefits, it also has some limitations. It may not be supported by all browsers, especially older ones. Also, it doesn’t provide server-side validation, which is necessary to ensure data integrity and security. Therefore, it’s recommended to use HTML5 form validation in conjunction with server-side validation.
How can I disable HTML5 form validation?
You can disable HTML5 form validation by adding the “novalidate” attribute to your form element. This can be useful in situations where you want to handle validation manually or using a different method.
Can I use HTML5 form validation for multiple fields?
Yes, you can use HTML5 form validation for multiple fields. Each input element can have its own validation rules, specified using attributes like required, pattern, min, max, etc. The form will not be submitted unless all fields pass their respective validation checks.
How can I validate email addresses using HTML5 form validation?
You can validate email addresses using HTML5 form validation by setting the type attribute of your input element to “email”. This will automatically validate the input data against a basic email pattern. For more complex validation, you can use the pattern attribute with a regular expression.
What is the role of CSS in HTML5 form validation?
CSS plays a significant role in HTML5 form validation. It allows you to style the form and the validation messages, making them more user-friendly. You can use CSS to highlight invalid fields, customize the appearance of error messages, and more.
How can I test if my HTML5 form validation is working correctly?
You can test your HTML5 form validation by trying to submit the form with invalid data. If the validation is working correctly, the form should not be submitted, and you should see the appropriate error messages. You can also use developer tools in your browser to inspect the form and check the validation rules.
Ian Oxley has been building stuff on the Web professionally since 2004. He lives and works in Newcastle-upon-Tyne, England, and often attends local user groups and meetups. He's been known to speak at them on occasion too. When he's not in front of a computer Ian can be found playing guitar, and taking photos. But not usually at the same time.