With the recent innovations of HTML 5 and CSS 3, form validation has been passed (in some form) back to the browser. What this means is that we can create powerful HTML forms before passing data to the server to validate via PHP, Ruby or ASP.
This tutorial takes you through how to create a simple login form with easy HTML validation patters and rules. With CSS we’ll be able to clearly identify where the user needs to improve their inputs and style the elements accordingly.
What We’re Covering
This is what I’ll be taking you through today:
See the Pen ftjnv by lawnch (@lawnch) on CodePen.
Resetting the CSS
As per usual, we need to reset browsers styling’s to treat our elements similarly for all users. This is done by using the CSS wildcard selector: *
. Additionally we want to style our body element. Both of the following aren’t required to make the tutorial work.
[css]* {
margin: 0;
padding: 0;
outline: none;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
body {
background: #eee;
color: #444;
-webkit-font-smoothing: antialiased;
font-family: "Open Sans", Arial, Helvetica, Geneva, sans-serif;
font-size: 16px;
font-weight: 400;
height: auto !important;
height: 100%;
line-height: 1.6em;
min-height: 100%;
}[/css]
Those with a keen eye may notice the inclusion of “Open Sans” font-family; this isn’t a default font. To include this font on your website for use in CSS you need to include it from the Google Font Library. To do this you simply add the following between your <head>
tags.
[html]link href="http://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,400,300,600" rel="stylesheet" type="text/css"[/html]
Modern HTML Heading Style
The use of HTML headings on your webpages is very important, not only for the end-user but for bots/spiders such as Googlebot. They help identify clear page structure and improve the accessibility of your website. For that reason, styling them well is very important. For this tutorial we’ll create a minimalist heading style, which means taking the bold style off but increasing the size.
The CSS for that is the following:
[css]h2 {
color: rgb(34,34,34);
font-size: 2.2em;
font-weight: 200;
margin: 0 0 24px 0;
}[/css]
Notice, I’ve added a 24px margin to the bottom of the heading to space out preceding elements.
Creating the Login Box
To make the form stand out we need to wrap it in a box design. For this we’re going to use the new <section>
element. This acts very much like a traditional <div>
element, but provides greater structure within the syntax – better for bots.
If you’re worried about using new HTML 5 elements in older browsers such as IE 8, simply include this code in your header –
[html]
<!–HTML 5 + IE HACK–><!– [if lt IE 9]><img src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7" data-wp-preserve="%3Cscript%20src%3D%22http%3A%2F%2Fhtml5shim.googlecode.com%2Fsvn%2Ftrunk%2Fhtml5.js%22%3E%3C%2Fscript%3E" data-mce-resize="false" data-mce-placeholder="1" class="mce-object" width="20" height="20" alt="<script>" title="<script>" /><![endif]–>
[/html]
Now let’s add the box HTML –
[html]
<section id="loginBox">
</section>
[/html]
Within the CSS we want to make sure the box stands out. In the example I’ve specified a light grey body background color, so setting a white background color for the body will make our content “pop”. Additionally, we want to add some nice rounded corners, padding and a slight shadow on the box to give the modern feel to the design.
[css]section#loginBox {
background-color: rgb(255,255,255);
border: 1px solid rgba(0,0,0,.15);
border-radius: 4px;
box-shadow: 0 1px 0 rgba(255,255,255,0.2) inset, 0 0 4px rgba(0,0,0,0.2);
margin: 40px auto; /*aligns center*/
padding: 24px;
width: 500px;
}[/css]
An important part of the above code is the margin:
[css]margin: 40px auto; /*aligns center*/[/css]
What this does is add a 40px margin (gap) above and below the box, but by using auto for the left and right values, we can center the box on the page.
Designing the Form
The first key to a good form is the use of form labels, these are pieces of text that identify the different inputs and when clicked they focus the relevant field. When creating my forms I like to wrap these around the input to give structure to the forms.
[html]<label for="username">
Username:
<input type="text" name="username" id="username" />
</label>[/html]
The important link here is between for="username"
and id="username"
on the respective elements. These attributes allow you to click the text and focuses the relevant form element for the user.
Styling the label is very simple, but for our design we want each form element on a new line. As a result, we need to style labels as display: block
.
[css]form.minimal label {
display: block;
margin: 6px 0;
}[/css]
Next we want to add a basic style to the form elements. Within CSS 3 we can use specific selectors to ensure we only style the type of inputs we want to. Example below:
[css]form.minimal input[type="text"],
form.minimal input[type="email"],
form.minimal input[type="number"],
form.minimal input[type="search"],
form.minimal input[type="password"],
form.minimal textarea {
background-color: rgb(255,255,255);
border: 1px solid rgb( 186, 186, 186 );
border-radius: 2px;
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.08);
-moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.08);
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.08);
display: block;
font-size: 14px;
margin: 6px 0 12px 0;
padding: 8px;
text-shadow: 0 1px 1px rgba(255, 255, 255, 1);
width: 90%;
-webkit-transition: all 0.1s linear;
-moz-transition: all 0.1s linear;
-o-transition: all 0.1s linear;
transition: all 0.1s linear;
}[/css]
Let me break that down for you –
Background-color:
first of all, we need to set the background color to white, which is the opposite to our dark textBorder:
we’ve set a light grey border using the RGB color index, you may also use HEXBorder-radius:
this will give us a nice 2px rounded corner. Increase this number to increase the roundness.Box-shadow:
to give the impression the form fields are indented within the page there’s an inset box shadow of very light blackDisplay:
block; setting this will push the element onto its own lineText-shadow:
a white text shadow has been added to allow for additional valid and invalid styling – currently this isn’t requiredTransition:
setting the transition to 0.1 seconds for all styles, this adds a nice effect when changing styles.
All the above styles have been declared for multiple elements at once, defined by linking the rules with a ,
.
When the user clicks inside the form elements we want to identify this to them. This is done through the use of the :focus
selector. Again, we can define this for multiple elements at once. Also, as we’ve specified a transition time, the changes identified below will appear animated.
[css]form.minimal input[type="text"]:focus,
form.minimal input[type="email"]:focus,
form.minimal input[type="number"]:focus,
form.minimal input[type="search"]:focus,
form.minimal input[type="password"]:focus,
form.minimal textarea:focus,
form.minimal select:focus {
border-color: #4195fc;
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 8px #4195fc;
-moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 8px #4195fc;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 8px #4195fc;
color: rgb(0,0,0);
}[/css]
The key here is that we’ve added a nice blue border and blue glow around the form elements, very similar to Bootstrap and Twitter.
Working with HTML Validation
In server-side coding languages such as PHP, using regex (regular expressions) for validation is common place. Nowadays you can use it within the browser. This allows developers to manage validation before passing it to the server, saving server resources.
To utilise regex in HTML we need to use the pattern attribute within the input
element.
Username Validation
The first regex pattern we want to use is for the username input. We want to limit usernames to alphanumeric characters with underscores, periods and hyphens, and require between 8 and 20 characters. This means special characters such as “[” and “/” won’t work, as well as spaces. To do this we do:
[js]^[a-zA-Z][a-zA-Z0-9-_\.]{8,20}$[/js]
Breaking that down. The string must start with a letter, then either a-z (lowercase letters), A-Z (uppercase letters), 0-9 (numbers), underscores, periods and hyphens are allowed, and it must be between 8 and 20 characters.
Password Validation
Secondly, we want to validate the password field. It’s important to prompt users to enter strong password’s when using your system as it increases its overall integrity. The following pattern requires 1 uppercase letter, 1 lowercase and 1 number or special character:
[js](?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$[/js]
This regex is much more complex than the username expression. If you wish to fully understand how this works, I recommend reading posts on regular-expressions.info.
Creating the Form HTML
Once we’ve decided on the HTML validation, we can pull all the HTML together to create our form:
[html]
<form method="post" class="minimal">
<label for="username">
Username:
<input type="text" name="username" id="username" placeholder="Username must be between 8 and 20 characters" pattern="^[a-zA-Z][a-zA-Z0-9-_\.]{8,20}$" required="required" />
</label>
<label for="password">
Password:
<input type="password" name="password" id="password" placeholder="Password must contain 1 uppercase, lowercase and number" pattern="(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$" required="required" />
</label>
<button type="submit" class="btn-minimal">Sign in</button>
</form>
[/html]
The final piece of the HTML puzzle is including the placeholder
attribute. This gives the input some default text that disappears on focus (when the user clicks inside the input). This is now simply done using:
[html]placeholder="Enter your text here"[/html]
Validating with CSS – :valid and :invalid
CSS 3 has introduced two form selectors, :valid and :invalid, which work really nicely with the pattern
and required
attributes. As you notice in the example, the form fields borders turn red when initially selected. This is because they’re invalid.
To style invalid form elements in CSS you simply do:
[css]form.minimal input[type="text"]:invalid:focus,
form.minimal input[type="email"]:invalid:focus,
form.minimal input[type="number"]:invalid:focus,
form.minimal input[type="search"]:invalid:focus,
form.minimal input[type="password"]:invalid:focus,
form.minimal textarea:invalid:focus,
form.minimal select:invalid:focus {
border-color: rgb(248,66,66);
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 8px rgb(248,66,66);
-moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 8px rgb(248,66,66);
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 8px rgb(248,66,66);
}[/css]
By adding :focus
to the rule we only show the invalid style when the input is selected. You don’t have to do this. You can simply do:
[css]input:invalid { color: red; }[/css]
Styling the Button
As I’ve covered this code in depth within a previous post, I won’t break it down too much. If you want a full, in depth tutorial on CSS 3 buttons.
Utilising my previous CSS button code, I’ve implemented a simple hover and clicked button state to match the form. The colors have been picked to match the borders of input elements and maintain the minimalist style.
[css]/*BUTTON DESIGN*/
[class*=’btn-‘] {
border: none;
border-bottom: 2px solid rgba(0,0,0,.15);
border-top: 1px solid rgba(255,255,255,.15);
border-radius: 3px;
color: #fff;
display: inline-block;
font: -webkit-small-control;
font-size: .7em;
letter-spacing: 1px;
line-height: 140%;
padding: 10px 20px;
text-decoration: none;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.25);
text-transform: uppercase;
-webkit-transition: all 0.1s linear;
-moz-transition: all 0.1s linear;
-o-transition: all 0.1s linear;
transition: all 0.1s linear;
}
.btn-minimal {
background-color: rgb(255,255,255);
border-radius: 0;
border: 1px solid rgb( 186, 186, 186 );
color: rgb( 186, 186, 186 );
text-shadow: 0 1px 1px rgba(255, 255, 255, 1);
}
.btn-minimal:hover {
background-color: #4195fc;
border: 1px solid rgba(0,0,0,.1);
color: rgb(255,255,255);
cursor: pointer;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.25);
}
.btn-minimal:active {
box-shadow: 0 1px 1px rgba(0,0,0,0.15) inset;
text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.25);
}[/css]
I’ve added an :active
state to the buttons. This is when the button is clicked, an inset drop shadow is added to make it look pressed down – snazzy!
Full code:
HTML:
[html]<body>
<section id="loginBox">
<h2>Login</h2>
<form method="post" class="minimal">
<label for="username">
Username:
<input type="text" name="username" id="username" placeholder="Username must be between 8 and 20 characters" pattern="^[a-zA-Z][a-zA-Z0-9-_\.]{8,20}$" required="required" />
</label>
<label for="password">
Password:
<input type="password" name="password" id="password" placeholder="Password must contain 1 uppercase, lowercase and number" pattern="(?=^.{8,}$)((?=.*\d)|(?=.*\W+))(?![.\n])(?=.*[A-Z])(?=.*[a-z]).*$" required="required" />
</label>
<button type="submit" class="btn-minimal">Sign in</button>
</form>
</section>
</body>[/html]
CSS
[css]* {
margin: 0;
padding: 0;
outline: none;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
body {
background: #eee;
color: #444;
-webkit-font-smoothing: antialiased;
font-family: "Open Sans", Arial, Helvetica, Geneva, sans-serif;
font-size: 16px;
font-weight: 400;
height: auto !important;
height: 100%;
line-height: 1.6em;
min-height: 100%;
}
h2 {
color: rgb(34,34,34);
font-size: 2.2em;
font-weight: 200;
margin: 0 0 24px 0;
}
/*BUTTON DESIGN*/
[class*=’btn-‘] {
border: none;
border-bottom: 2px solid rgba(0,0,0,.15);
border-top: 1px solid rgba(255,255,255,.15);
border-radius: 3px;
color: #fff;
display: inline-block;
font: -webkit-small-control;
font-size: .7em;
letter-spacing: 1px;
line-height: 140%;
padding: 10px 20px;
text-decoration: none;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.25);
text-transform: uppercase;
-webkit-transition: all 0.1s linear;
-moz-transition: all 0.1s linear;
-o-transition: all 0.1s linear;
transition: all 0.1s linear;
}
.btn-minimal {
background-color: rgb(255,255,255);
border-radius: 0;
border: 1px solid rgb( 186, 186, 186 );
color: rgb( 186, 186, 186 );
text-shadow: 0 1px 1px rgba(255, 255, 255, 1);
}
.btn-minimal:hover {
background-color: #4195fc;
border: 1px solid rgba(0,0,0,.1);
color: rgb(255,255,255);
cursor: pointer;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.25);
}
.btn-minimal:active {
box-shadow: 0 1px 1px rgba(0,0,0,0.15) inset;
text-shadow: 0 -1px 1px rgba(0, 0, 0, 0.25);
}
/*SECTION CONTAINER*/
section#loginBox {
background-color: rgb(255,255,255);
border: 1px solid rgba(0,0,0,.15);
border-radius: 4px;
box-shadow: 0 1px 0 rgba(255,255,255,0.2) inset, 0 0 4px rgba(0,0,0,0.2);
margin: 40px auto; /*aligns center*/
padding: 24px;
width: 500px;
}
/*FORM*/
form.minimal label {
display: block;
margin: 6px 0;
}
form.minimal input[type="text"],
form.minimal input[type="email"],
form.minimal input[type="number"],
form.minimal input[type="search"],
form.minimal input[type="password"],
form.minimal textarea {
background-color: rgb(255,255,255);
border: 1px solid rgb( 186, 186, 186 );
border-radius: 2px;
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.08);
-moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.08);
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.08);
display: block;
font-size: 14px;
margin: 6px 0 12px 0;
padding: 8px;
text-shadow: 0 1px 1px rgba(255, 255, 255, 1);
width: 90%;
-webkit-transition: all 0.1s linear;
-moz-transition: all 0.1s linear;
-o-transition: all 0.1s linear;
transition: all 0.1s linear;
}
form.minimal input[type="text"]:focus,
form.minimal input[type="email"]:focus,
form.minimal input[type="number"]:focus,
form.minimal input[type="search"]:focus,
form.minimal input[type="password"]:focus,
form.minimal textarea:focus,
form.minimal select:focus {
border-color: #4195fc;
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 8px #4195fc;
-moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 8px #4195fc;
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 8px #4195fc;
color: rgb(0,0,0);
}
form.minimal input[type="text"]:invalid:focus,
form.minimal input[type="email"]:invalid:focus,
form.minimal input[type="number"]:invalid:focus,
form.minimal input[type="search"]:invalid:focus,
form.minimal input[type="password"]:invalid:focus,
form.minimal textarea:invalid:focus,
form.minimal select:invalid:focus {
border-color: rgb(248,66,66);
-webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 8px rgb(248,66,66);
-moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 8px rgb(248,66,66);
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1), 0 0 8px rgb(248,66,66);
}[/css]
Conclusion
I hope you’ve enjoyed this tutorial. Feel free to ask questions below and post links to where you’ve used it.
Subscribe for Updates
Get notified about my latest content first and receive invitations for subscriber only competitions.
Do you minbd if I quuote a few of your articles as long as I provide credit and sources back to your website?
My website iss in the very samme area of interest as yours and my visitors would dfinitely benefot from a lot
of the information yyou present here. Please
let me know if this ok with you. Regards!
Thanks for this,
I’m just wondering if there’s a way to make this form pop up when visiting a website? Like an onload event. And instead of relaying the form details to a database, could it not send the form details to an e-mail address?
Thanks.