input type="url", validation and user interfaces
Recently a friend messaged me about the url
input type, and how to
prevent Opera from automatically prepending http:// to the value of a
URL input field if it is missing. I think I've found a workaround, but
first, I want to discuss the url
input type, and how different
browsers handle it.
HTML5 introduces several additional types for the input
element.
One goal of these additional types is to offload error checking from the
JavaScript layer to the browser. The HTML5 specification includes rules
and patterns for data validation, including for URLs with the url
attribute value.
According to the HTML5 specification, a URL is valid when it is not an empty string, and is a “valid absolute URL.” A complete definition of what constitutes a valid URL can be found in RFC 3986 and RFC 3987. The short version is that a valid URL must, at minimum, consist of a scheme (https://, ftp://, gopher://) and a host name. If it does not, validation should fail, and the browser should throw an error.
Now most recent browsers* take the following steps when
it encounters an invalid URL such as foo.com
or example:80
.
- Fire an
invalid
event on the element in question. - Display an error message to the user.
- Prevent form submission.
To prevent careless input errors and guarantee validation, Opera will
automatically prepend
http://
to the value of a URL input field if it is missing when the field loses
focus (and if no pattern attribute has been added). This means that the
invalid event usually will not be fired.
Of course, "most recent browsers" does not mean "all." To date,
Safari will fire the invalid
event, but it will do so
silently. No error message will be shown to the user. Form submission
will succeed. The value submitted will be the same as what was entered
by the user. Android's WebKit behaves much the same way.
Safari also does something else differently on mobile devices: it
shows a keyboard layout that is optimized for typing URLs, complete with
a .com virtual button.
Back to my friend's use case: he wanted the benefit of mobile Safari's
UI sugar, so he was using <input type="url">
. He was unconcerned with
whether the URL was valid because he was using server-side validation.
His primary goal was ease of data entry for domain names on iOS
devices.
However: that isn't really the purpose of <input type="url">
.
Validation is, and a domain name by itself is not a valid URL.
But since the ship has sailed, the horse has left the barn, and the chickens have flown the coop, let's talk about how to prevent Opera from automatically prepending http:// to the value of a URL input field.
To do this, we need to do two things:
- Add a
novalidate
attribute to the form element. - Add a null
pattern
attribute to the field element.
For example:
<form action="../form.php" method="post" novalidate>
<input type="url" name="uri" id="uri" value="" pattern="">
<button type="submit">submit</button>
</form>
The novalidate
attribute turns off client-side validation for the
entire form. The pattern attribute override's Opera's native validation
checking.
See for yourself. This will still trigger the URL-entry keyboard layout in iOS browsers, while killing Opera's prepending.
If you use this technique, keep in mind that server-side validation is even more important. Because we are not providing any constraints on this data, we have increased our chances of getting invalid or malicious data. You should be validating anyway, however, since it is not 100% possible to guarantee that the data reaching our form script has actually come from our form.
*And by "recent browsers," I mean the latest versions of Opera, Chrome, Firefox, and the forthcoming Internet Explorer 10, but not IE9.