
Validation of forms has been a pedantic exercise since the advent of the web. First came server validation. It then evolved into client-side validation to validate the results in the browser. Now we have such giants as HTML5 and CSS3: the
chapter on HTML5
forms offers us new types for input fields and attributes that make it possible to check field restrictions.
The CSS3
base UI module provides several pseudo-classes that help us stylize the state of validity and change the appearance of the field depending on user actions. Let's take a look at the combination of both to create a CSS-based form validator that has fairly extensive browser support.
The more we can give hints to the user how to correctly fill out the form during the filling process, the less chance he will make a mistake. Take a look at
an example of CSS3 form validation in a browser that supports CSS3 UI pseudo-classes, such as Chrome 4+, Safari 5+, or Opera 9.6+. I used CSS3 UI pseudo-classes and HTML5 form attributes to create CSS-based validation. Let's see how it works.
CSS3 UI pseudo-classes
The UI module contains several pseudo-classes that help to stylize the form fields depending on their state.
- valid
- invalid
- required
- optional
- in-range
- out-of-range
- read-only
- read-write
In the demo shown above, I used the
required
,
invalid
and
valid
pseudo-classes to perform the check.
input:focus:required:invalid {
background: pink url(ico_validation.png) 379px 3px no-repeat;
}
input:required:valid {
background-color: #fff;
background-position: 379px -61px;
}
* This source code was highlighted with Source Code Highlighter .
Since we want to indicate that the field is not valid only when it is active, we use the
focus
pseudo-class to cause the
invalid
style for the field (Naturally, to designate all required fields as not valid will be a bad design decision from the very beginning).
')
To draw attention to the mandatory fields that did not pass the test, a style is displayed showing an icon with an exclamation mark, which warns the user that something must be entered. After checking the field, if it passes the restrictions, the
valid
pseudo-class is called. Now we remove the
focus
pseudo-class so that the green check mark indicating the validity of the field remains.
All the values of the pseudo-classes listed above speak for themselves. The
in-range
and
out-of-range
pseudo-classes should be used in conjunction with the
min
and
max
attributes, be it
input[type=range]
or any other field that accepts these attributes. For example, if a user enters a value outside the constraints, we can use a pseudo-class to change the style that takes this state into account. In addition, we can do the same if the value falls within the range of restrictions.
Currently, range pseudo-classes only support Opera. In the near future support will appear in other browsers.
Additional types and attributes that help us
In HTML5 forms, new
input
types are also implemented, such as
email
,
url
and
number
. For example,
email
calls the
valid
pseudo-class when the user enters a valid e-mail address, the same happens for the
numer
and
url
fields. Checking the
url
field is different in different browsers. In Opera, typing
"http://"
field is denoted as valid, in Crome,
"http://w"
, and in Safari, simply typing
"http:"
.
There are a few more attributes that help in field validation, such as
placeholder
,
required
,
maxlength
,
pattern
,
min
,
max
and
step
.
< input id ="postcode" name ="postcode" type ="number" min ="1001" max ="8000" maxlength ="4" required />
* This source code was highlighted with Source Code Highlighter .
The postcode field uses a new type of
number
and several new attributes. In Australia, a zip code may consist of only 4 digits, so we set the
maxlength
attribute to limit it. We also want to limit the maximum and minimum index values, for this we use the
min
and
max
attributes. The
required
attribute speaks for itself (required field).
We can use the
step
attribute, for bigger restriction together with
min
and
max
. By default, step is set to one. Therefore, any number set in the range between
min
and
max
is valid. If you change the value of
step
to 100, then the value will be checked in the range from
min
to
max
in increments of 100. For example, the
step
attribute will be valid for field values of 1001, 1101, 1201, 1301, and so on.
Sample search
To call the pseudo-class
invalid
for a field with more specific restrictions, such as a phone number field, we can use the
pattern
attribute, which allows regular expressions to be used to check the field value.
< input type ="tel" id ="tel" name ="tel" pattern ="\d{10}" placeholder ="Please enter a ten digit phone number" required />
* This source code was highlighted with Source Code Highlighter .
In this example, the regular expression is very simple, "I accept only 10 digits and nothing more." Thus, the field will be invalid until the regular expression is executed. Notice that I used the
placeholder
attribute to give a hint to the user.
In reality, we can set more powerful conditions to the value of the
pattern
attribute, by adding more complex regular expressions, for example, for the password field:
< input id ="password" name ="password" type ="password" title ="Minimum 8 characters, one number, one uppercase and one lowercase letter" required pattern ="(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[AZ])(?=.*[az]).*" />
* This source code was highlighted with Source Code Highlighter .
Now we have more stringent restrictions, which allows the user to enter a more secure password. The password must be at least 8 characters, contain one number, one lowercase and one uppercase letter.
To help the user, we use the
title
attribute. We do not use the
placeholder
attribute in this case, since it is intended only for short messages.
Adding helpful hints
If the user does not hover over the field, he will never see additional instructions in the
title
attribute. You may notice that useful tips appear for the
phone
,
postcode
and
password
fields, this helps when the user needs additional instructions.
< input id ="password" type ="password" />
< p class ="validation01" >
< span class ="invalid" > Minimum 8 characters, one number, one uppercase letter and one lowercase letter </ span >
< span class ="valid" > Your password meets our requirements, thank you. </ span >
</ p >
* This source code was highlighted with Source Code Highlighter .
The markup above contains additional containers for both states - the field is valid and not valid. Thus, when the field is not valid, it will contain information that will help the user enter valid data. When everything is correct, our message and a green check mark convince him that the field is filled correctly.
.validation01 {
background: red;
color: #fff;
display: none;
font-size: 12px;
padding: 3px;
position: absolute;
right: -110px;
text-align: center;
top: 0;
width: 100px;
}
input:focus + .validation01 {
display: block;
}
input:focus:required:valid + .validation01 {
background: green;
}
input:focus:required:valid + .validation01 .invalid {
display: none;
}
input:focus:required:invalid + .validation01 .valid {
display: none;
}
* This source code was highlighted with Source Code Highlighter .
To show or hide the hint, depending on the state of the field, we can specify the field a chain of pseudo-classes with the addition of a neighboring element containing the desired hint. After the field has been filled in correctly, the background color changes to green and the corresponding message is displayed.
Ux problems of this approach
There is one major problem in using the invalid pseudo-class when the field is required and there are additional conditions that must be met. For example, when a field is required and its type is email, it will not be valid until all its conditions are met and styles will be used for
invalid
from the very beginning, even before the user has entered anything. That is why we used the
focus
pseudo-class to show
invalid
styles only when this field is in focus. This is not the optimal solution: if the user leaves this field without fulfilling the requirements of the validator, it will not be shown that the data entered is not correct until he returns to editing this field.
The solution to this was the addition of
an undefined pseudo-class available for
radio
and
checkbox
input
. Technically, the fields having more conditions than just required, while empty are neither valid nor valid, but rather uncertain. This idea can correct the
invalid
state and allow the optimal styles to be applied to fields depending on the validation state.
In addition, we can do some fairly large functionality without JavaScript. We can tell what state the field has if it is in focus, if required, tell it to conform to a specific pattern specified in the regular expression, specify the minimum and maximum values, and more. But what if this is not enough? What if we want more? Fortunately, the HTML5 Forms chapter also defines a
validation constraint checking API .
API validation constraint checking
Along with all the new attributes, input and CSS3 types, pseudo-classes, the HTML5 Forms chapter also defines a simple JavaScript API that allows you to extend the validation capabilities of forms with several useful built-in methods, attributes, and events. Let's take a look at the
updated demo that enables the API to check validation constraints.
Each form field has a new
validity
attribute. The
validity
attribute returns a
ValidityState
object, which provides the current state of validity. The
ValidityState
object contains several Boolean variables that determine which state of a particular element. Basically, their answers are true / false which enable the developer to understand what is wrong with the field:
- valueMissing
This attribute returns true if the required field is empty. - typeMismatch
Applies to new input types. For example, if the email value is incorrect, this attribute will return true. - patternMismatch
If the element contains the pattern attribute and its value does not match the conditions of the regular expression, the attribute returns true. - tooLong
If the value of any element exceeds its maxlength, this attribute returns true. - rangeUnderflow and rangeOverflow
If the value of the element goes beyond the min or max attributes, then this attribute will return true. - stepMismatch
When an element with the step attribute does not match the required value, this attribute returns true. - valid
If any of the above values returns true, then this attribute will return false. Otherwise, if all the conditions are met, it will return true.
That's not all
The
invalid
event has another useful function. It will be called by the field as long as its value remains invalid. So, with its help, we can change the styles of the fields according to their current state.
In addition, the
checkValidity()
method can be performed on any single field or form as a whole, returning true or false.
Apply to demo
Let's take our previous demo and improve it using the validation constraint API. By accepting what we learned from Luke Wroblewski in the
Inline Validation in Web Forms article and our own data, we can apply these ideas in our demo form to create the best validator.
The first thing we can fix is instant styling for a non-valid field. Instead of immediately changing the style of the field, showing that the user enters incorrect data, we wait until the user leaves the field.
If the data meets the requirements, even while the field is in focus, we will let the user know that the field is valid. We do this by adding events to the
input
to check the validity of the field. If everything is correct, then we update the styles and show the result immediately.
If the field has an incorrect value, and the user moves to the next field, the
blur
event checks the validity of the field, and then applies the
invalid
styles. So that the user can know about the error. This will keep displaying error styles until corrected.
What about old browsers?
In all topics, new products and support for modern browsers are discussed, all this is good, but let's not forget about the real world, where we must also support outdated browsers. For this, I wrote a
script to help do this.
For browsers that do not support HTML5 forms and API validation restrictions, the script emulates this functionality. For browsers that support this functionality, the script will determine if there is support and the functionality will be executed by means of the browser. Let's take a look at the
next update demo with the added script. Check in IE or Firefox to see the functionality of the script, the same as for browsers that support the desired functionality.
Browser Support
The script is tested and works in the following browsers:
- IE6 +
- Firefox 1+ - FF4 will have built-in support;
- Chrome 4+ - Built-in support;
- Safari 3.2+ - Safari 5 has built-in support;
- Opera 9.6+ - Built-in support.
Functions emulated by the script:
- Each field has a
validity
object that allows you to find out the current state; - The
checkValidity()
method is checkValidity()
indicating that the form or some individual element is not valid; - Attribute support
placeholder
, required
, min
, max
and step
; - Support for
placeholder
and required
attributes for textarea
; - Attribute support
required
for select
element; - The email and
url
types for input
will be checked using the built-in regular expression.
Abundance of checks
Browser support for HTML5 forms and the CSS3 UI model is starting to improve. Opera9 will continue to support
Web Forms 2.0 until they are combined with HTML5 forms. Chrome has added support since version 4, Safari received it recently with the release of version 5, Firefox should add support in the upcoming beta version 4 and IE9, if they continue their development at this pace, should also get support.
We can do amazing things with the appropriate sections of CSS3 and HTML5. All browsers improve support and this way of checking forms becomes viable, able to check any simple or complex forms.