41
Validating Forms (AND MORE) WITH THE HTML5 Pattern Attribute @cliener

Validating forms (and more) with the HTML5 pattern attribute

  • Upload
    cliener

  • View
    3.584

  • Download
    0

Embed Size (px)

DESCRIPTION

In the past, validating forms in the client has typically required doing some heavy lifting with JavaScript. But you may not know HTML5 changes all that. Browsers now check that the content of an input match its type (and we've got new types like email, url and number to make that even more useful). But, what you might not know about is the pattern attribute, which lets us use regular expressions directly in HTML to specify what format the user's input should have. In this session, Chris Lienert will look at some of the common regex patterns you can use to validate user input, coupled with some of the many tricks he's learned to help users complete those forms we all love to hate.

Citation preview

Page 1: Validating forms (and more) with the HTML5 pattern attribute

Validating Forms(AND MORE)

WITH THEHTML5 Pattern

Attribute

@cliener

Page 2: Validating forms (and more) with the HTML5 pattern attribute

HTML5 RECAP

http://wufoo.com/html5/Before I get stuck into patterns, I’ll quickly go through some of the important parts of HTML5 forms. If you want to play along at home, have a look at Wufoo’s HTML Forms guide.

Page 3: Validating forms (and more) with the HTML5 pattern attribute

HTML5 RECAP

<input  type="email">

Most of the new input types come with awesome custom keyboards for iOS and more recent Android (amongst others). Some browser versions offer basic validation in but inconsistent implementations mean they can’t be relied upon.The key new inputs types are “email”,

Page 4: Validating forms (and more) with the HTML5 pattern attribute

HTML5 RECAP

<input  type="tel">

“tel”,

Page 5: Validating forms (and more) with the HTML5 pattern attribute

HTML5 RECAP

<input  type="url">

“url” and

Page 6: Validating forms (and more) with the HTML5 pattern attribute

<input  type="number">

HTML5 RECAP

“number”.

Page 7: Validating forms (and more) with the HTML5 pattern attribute

<input  type="datetime">

HTML5 RECAP

Unfortunately “datetime”, “time” and “year” input types have been marked as “in danger” by the W3C due to poor and inconsistent browser support. There’s something of a chicken and egg situation when it comes to standards and browser support. Unfortunately for the HTML5 date and time inputs,

Page 8: Validating forms (and more) with the HTML5 pattern attribute

the chicken looks something like this.

Page 9: Validating forms (and more) with the HTML5 pattern attribute

<input  required>

HTML5 RECAP

Important attributes to note are “required”,

Page 10: Validating forms (and more) with the HTML5 pattern attribute

<input  placeholder=              "dd/mm/yyyy">

HTML5 RECAP

“placeholder”

Page 11: Validating forms (and more) with the HTML5 pattern attribute

PATTERNS

<input  pattern="/d*">

and, of course, “pattern”. Patterns allow you to provide a regular expression string primarily for input validation. A numeric regulation expression like the this one can trigger a numeric keyboard. You’ll often see the above pattern as “[0-9]*” because most people don’t know how to write regular expressions to save themselves.

Page 12: Validating forms (and more) with the HTML5 pattern attribute

NOW YOU HAVE TWO PROBLEMS

http://evolt.org/node/36435I can’t remember the origin so I’ll call it an old saying: “You have a problem which can be solved with a regular expression. Now you have two problems.”I won’t pretend regular expressions are the easiest to write however a good guide the one on Evolt will certainly make life easier for you.

Page 13: Validating forms (and more) with the HTML5 pattern attribute

PATTERNS

/\d*/.test("12345");>>>  true

I find the JS console (in a browser near you) are a handy way to test out regular expressions. This one matches any numeric value

Page 14: Validating forms (and more) with the HTML5 pattern attribute

/\d*/.test("Once  I  caught  a              fish  alive");>>>  false

PATTERNS

And correctly returns false to a string.

Page 15: Validating forms (and more) with the HTML5 pattern attribute

POSTCODE

/\d{4}/.test("605");>>>  false

Australian postcodes are easily matched with this pattern - exactly four digits - returning false here for “605”

Page 16: Validating forms (and more) with the HTML5 pattern attribute

/\d{4}/.test("6050");>>>  true

POSTCODE

and true here for a correct value.

Page 17: Validating forms (and more) with the HTML5 pattern attribute

YEAR

/\d{4}|\d{2}/.test("13");>>>  true

Getting slightly more complex with a pipe which acts as an “or” switch, we can match either two or four digit years.

Page 18: Validating forms (and more) with the HTML5 pattern attribute

TIME

/(([0-­‐1]\d)|(2[0-­‐3])):[0-­‐5]\d/.test("08:37");>>>  true

Square brackets specify a range of values, round brackets group sub-expressions together: here matching a twenty hour time value.

Page 19: Validating forms (and more) with the HTML5 pattern attribute

/(([0-­‐1]?\d)|(2[0-­‐3]))(:|\.)[0-­‐5]\d/.test("8.37");>>>  true

TIME

With a slight modification, we’re now matching a wider range of natural inputs.

Page 20: Validating forms (and more) with the HTML5 pattern attribute

DATE

/\d{2}\/\d{2}\/\d{4}/.test("24/10/2013");>>>  true

Dates seem fairly straight-forward

Page 21: Validating forms (and more) with the HTML5 pattern attribute

/\d{2}\/\d{2}\/\d{4}/.test("99/99/9999");>>>  true

DATE

but are a lot more complex than they seem.

Page 22: Validating forms (and more) with the HTML5 pattern attribute

/(?=\d)(?:(?:31(?!.(?:0?[2469]|11))|(?:30|29)(?!.0?2)|29(?=.0?2.(?:(?:(?:1[6-­‐9]|[2-­‐9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00)))(?:\x20|$))|(?:2[0-­‐8]|1\d|0?[1-­‐9]))([-­‐\/])(?:1[012]|0?[1-­‐9])\1(?:1[6-­‐9]|[2-­‐9]\d)?\d\d(?:(?=\x20\d)\x20|$))?/.test("99/99/9999");>>>  false

DATE

A bit more work and we end up with this.

Page 23: Validating forms (and more) with the HTML5 pattern attribute

At this point I can understand if you’re a little shocked, so I’ll pull it back a little.

Page 24: Validating forms (and more) with the HTML5 pattern attribute

EMAIL

/\w+@\w+\.\w+/.test("[email protected]")>>>  true

Email addresses are often something of a mine field but, on the surface, the pattern is fairly simple: “[email protected]

Page 25: Validating forms (and more) with the HTML5 pattern attribute

/\w+@\w+\.\w+/.test("cli+ner@                  server.com.au");>>>  true

EMAIL

Already we’re matching better than most email validation rules out there.

Page 26: Validating forms (and more) with the HTML5 pattern attribute

/\w+@\w+\.\w+/.test("[email protected]");>>>  true

EMAIL

Except the simplicity soon gets us unstuck when we get false positives. Given how scary date validation was, it’s tempting to see what Google has to offer

Page 27: Validating forms (and more) with the HTML5 pattern attribute

/(?:(?:\r\n)?[  \t])*(?:(?:(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[  \t]))*"(?:(?:\r\n)?[  \t])*)(?:\.(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]\000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[  \t]))*"(?:(?:\r\n)?[  \t])*))*@(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[  \t])*)(?:\.(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[  \t])*))*|(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[  \t]))*"(?:(?:\r\n)?[  \t])*)*\<(?:(?:\r\n)?[  \t])*(?:@(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[  \t])*)(?:\.(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[  \t])*))*(?:,@(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[  \t])*)(?:\.(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[  \t])*))*)*:(?:(?:\r\n)?[  \t])*)?(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[  \t]))*"(?:(?:\r\n)?[  \t])*)(?:\.(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[  \t]))*"(?:(?:\r\n)?[  \t])*))*@(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[  \t])*)(?:\.(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[  \t])*))*\>(?:(?:\r\n)?[  \t])*)|(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[  \t]))*"(?:(?:\r\n)?[  \t])*)*:(?:(?:\r\n)?[  \t])*(?:(?:(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[  \t]))*"(?:(?:\r\n)?[  \t])*)(?:\.(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[  \t]))*"(?:(?:\r\n)?[  \t])*))*@(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[  \t])*)(?:\.(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[  \t])*))*|(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[  \t]))*"(?:(?:\r\n)?[  \t])*)*\<(?:(?:\r\n)?[  \t])*(?:@(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[  \t])*)(?:\.(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[  \t])*))*(?:,@(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[  \t])*)(?:\.(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[  \t])*))*)*:(?:(?:\r\n)?[  \t])*)?(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[  \t]))*"(?:(?:\r\n)?[  \t])*)(?:\.(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[  \t]))*"(?:(?:\r\n)?[  \t])*))*@(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[  \t])*)(?:\.(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[  \t])*))*\>(?:(?:\r\n)?[  \t])*)(?:,\s*(?:(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[  \t]))*"(?:(?:\r\n)?[  \t])*)(?:\.(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[  \t]))*"(?:(?:\r\n)?[  \t])*))*@(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[  \t])*)(?:\.(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[  \t])*))*|(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[  \t]))*"(?:(?:\r\n)?[  \t])*)*\<(?:(?:\r\n)?[  \t])*(?:@(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[  \t])*)(?:\.(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[  \t])*))*(?:,@(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[  \t])*)(?:\.(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[  \t])*))*)*:(?:(?:\r\n)?[  \t])*)?(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[  \t]))*"(?:(?:\r\n)?[  \t])*)(?:\.(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|"(?:[^\"\r\\]|\\.|(?:(?:\r\n)?[  \t]))*"(?:(?:\r\n)?[  \t])*))*@(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[  \t])*)(?:\.(?:(?:\r\n)?[  \t])*(?:[^()<>@,;:\\".\[\]  \000-­‐\031]+(?:(?:(?:\r\n)?[  \t])+|\Z|(?=[\["()<>@,;:\\".\[\]]))|\[([^\[\]\r\\]|\\.)*\](?:(?:\r\n)?[  \t])*))*\>(?:(?:\r\n)?[  \t])*))*)?;\s*)/.test("[email protected]");>>>  true

http://www.codinghorror.com/blog/2005/02/regex-use-vs-regex-abuse.html

EMAIL

And here is 6.2KB of RFC standard-compliant email regular expression.

Page 28: Validating forms (and more) with the HTML5 pattern attribute

Which brings me to a major problem when regular expressions.

Page 29: Validating forms (and more) with the HTML5 pattern attribute

Unfortunately, a fair number of programmers out in the wild haven’t quite worked out regular expressions yet so you need to be really careful about what you’re write.

Page 30: Validating forms (and more) with the HTML5 pattern attribute

/([\w!#%&$'*+\-­‐=?^_`{|}~]+[\w!#%&$'*+\-­‐=?^_`{|}~.]+[\w!#%&$'*+\-­‐=?^_`{|}~]+|[\w!#%&$'*+\-­‐=?^_`{|}~]{1,2})@([A-­‐Za-­‐z0-­‐9-­‐]+\.)+[A-­‐Za-­‐z0-­‐9-­‐]+/.test("[email protected]");>>>  false

EMAIL

For the record, here’s my RFC-compliant email regular expression.

Page 31: Validating forms (and more) with the HTML5 pattern attribute

SECURITY

As a whole, password validation is awful.

Page 32: Validating forms (and more) with the HTML5 pattern attribute

SECURITY

Over-validation is a great way to make people hate you

Page 33: Validating forms (and more) with the HTML5 pattern attribute

SECURITY

because, as much as you might think otherwise, you don’t know as much about them as you think you do.

Page 34: Validating forms (and more) with the HTML5 pattern attribute

SECURITY

But then there are people like, presumably, Bob.

Page 35: Validating forms (and more) with the HTML5 pattern attribute

And here be dragyns. In the last couple of years, millions of passwords - hashed and otherwise - have been grabbed from various online services which means that everything we though we knew about password validation is, in essence, wrong. This also means that enforced password validation is probably wrong too. So, please don’t. Invest your energy into two factor authentication or something else that’s actually secure rather than incurring the wrath of the users who do know what they’re doing.

Page 36: Validating forms (and more) with the HTML5 pattern attribute

"4123  5678  9012  3456".replace(/(\s)/g,  "");>>>  "4123567890123456"

CREDIT CARDS

While I’ve shown how awesome regular expressions are for pattern validation, they can also manipulate data. Right here is everything you need to strip spaces from a credit card number so I can enter it with spaces as it is on my card. You no longer have any excuses.

Page 37: Validating forms (and more) with the HTML5 pattern attribute

ERROR MESSAGES

<input  pattern="\d{4}"  title="Please  enter  a  valid  postcode  e.g.  3000">

Rather crucial when doing pattern validation is presenting a meaningful error message to users. In HTML5, browsers are abusing the title attribute to this end. You can also set the .setCustomValidity() DOM property but title will work for most instances.

Page 38: Validating forms (and more) with the HTML5 pattern attribute

ERROR MESSAGES

The results aren’t perfect, but they’re a whole lot better than server validation.

Page 39: Validating forms (and more) with the HTML5 pattern attribute

In summary, are regular expressions better than kittens? I think the answer is definitively yes.

Page 41: Validating forms (and more) with the HTML5 pattern attribute

FURTHER READING

HTML5 Rocks: Constraint Validation: Native Client Side Validation for Web Formshttp://www.html5rocks.com/en/tutorials/forms/constraintvalidation/