Implementing the Floating Label Form Pattern
Using Matt Smith’s mobile form interaction design as a guide, we will create a stunning form interaction for the web that’s both beautiful and accessible using HTML, CSS and JavaScript.
Overview
Form design and interaction on the web can be a sensitive subject. A multiplicity of form accessibility concerns and best practices can make designing a compelling form interaction very difficult, as opposed to form design on native platforms.
Matt Smith recently created a compelling form interaction he posted to Dribbble:



Though designed for a native iOS application, this form interaction can be recreated for the web using HTML, CSS, and Javascript while also appeasing form accessibility concerns.
The floating label concept has stirred up quite some attention, leading to discussion and experiments all across the web.
Really cool demo by @zelph http://t.co/Szw1bE2tib implementing the super awesome floating label form interaction http://t.co/NhKfErgd2Q by @mds
— Brad Frost (@brad_frost) October 23, 2013
Rather than use the same form fields in Matt’s design, we will create a simple contact form you could use on your own website. So let’s dive in!
Form Anatomy
First, let’s observe and record the form interactions Matt has created. This will allow us to predetermine how our form should be marked up. It will also give us a good understanding of how to style the form and create its interactions with JavaScript.
Form Structure
The form has the following elements we can translate to HTML:
-
<label>
elements -
<input>
elements -
<textarea>
element -
placeholder
attributes



Form Element Interactions
By observing the interactions Matt has created, we can formulate rules for the interaction of the form elements we will be creating. These rules will be useful in creating our markup, style rules, and JavaScript interactions.
-
on page load:
-
<label>
elements - Hidden, emphasized with a highlight color.
-
<input>
&<textarea>
elements:- Show the element’s placeholder text.
-
-
on focus:
-
<label>
elements - If the label’s corresponding input field is empty, hide the label. Otherwise, de-emphasize the label’s color.
-
<input>
&<textarea>
elements:- If the field is empty, show the element’s placeholder text. Otherwise, show the text entered by the user.
-
-
on keyup:
-
<label>
elements - If the label’s corresponding input field is empty, hide the label. Otherwise, show the label.
-
<input>
&<textarea>
elements:- If the field is empty, show the placeholder text. Otherwise, show the text entered by the user.
-
-
on blur:
-
<label>
elements - If the corresponding input field is empty, hide the label. Otherwise, de-emphasize the color.
-
<input>
&<textarea>
elements:- If the field is empty, show the placeholder text. Otherwise, show the text entered by the user.
-
Now that we have determined the form’s HTML elements along with its interaction rules, we can begin creating it.
Basic HTML
Let’s start by getting some basic starter code.
1 |
<!doctype html>
|
2 |
<html lang="en"> |
3 |
<head>
|
4 |
<meta charset="utf-8"> |
5 |
<title>Contact Me</title> |
6 |
|
7 |
<!-- Viewport tag to make things responsive -->
|
8 |
<meta name="viewport" content="width=device-width, initial-scale=1"> |
9 |
|
10 |
<!-- Link to the stylesheet we will create -->
|
11 |
<link rel="stylesheet" href="styles.css"> |
12 |
|
13 |
<!-- HTML5 shiv for older browsers -->
|
14 |
<!--[if lt IE 9]>
|
15 |
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
16 |
<![endif]-->
|
17 |
</head>
|
18 |
<body>
|
19 |
|
20 |
<!-- Form Markup Will Go Here -->
|
21 |
|
22 |
<!-- Google’s hosted version of jQuery -->
|
23 |
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script> |
24 |
|
25 |
<!-- Link to the javascript file we will create -->
|
26 |
<script src="scripts.js"></script> |
27 |
</body>
|
28 |
</html>
|
Creating the Form Markup
Now let’s create the markup for our form:
1 |
<section class="container"> |
2 |
<h1 class="title">Contact Me</h1> |
3 |
<form id="form" class="form" action="#" method="get"> |
4 |
<ul>
|
5 |
<li>
|
6 |
<label for="name">Your Name:</label> |
7 |
<input type="text" placeholder="Your Name" id="name" name="name" tabindex="1"/> |
8 |
</li>
|
9 |
<li>
|
10 |
<label for="email">Your Email:</label> |
11 |
<input type="email" placeholder="Your Email" id="email" name="email" tabindex="2"/> |
12 |
</li>
|
13 |
<li>
|
14 |
<label for="message">Message:</label> |
15 |
<textarea placeholder="Message…" id="message" name="message" tabindex="3"></textarea> |
16 |
</li>
|
17 |
</ul>
|
18 |
<input type="submit" value="Send Message" id="submit"/> |
19 |
</form>
|
20 |
</section>
|
Here we setup a form container with a header of “Contact Me” and the corresponding form elements structured within list elements. Notice we also assigned the email field type="email"
. This provides contextual virtual keyboards for devices that support them as well as simple, browser supported validation for those browsers that support HTML5 input types. For those that do not, it becomes a simple text field.
What we have now are the very basics of a form that will work anywhere and is properly structured for simple accessibility.



Note: We are not covering server side form submission in this tutorial, so feel free to change the form’s submission method as needed.
Creating Basic Page Styles
We now have a working form in HTML. Now we are going to make our first step in progressive enhancement: applying CSS styles. Let’s create styles to make our form more visually appealing while also remembering to keep the form functional and accessible.
Let’s create some basic styling for the page and form container. In the <head>
of our document we created a link to a file named styles.css
, so we will create that file now and save it to the root of our project.
We begin by importing the styles from Eric Meyer’s CSS reset into our own file. You can grab those styles here and copy them into your own style sheet.
Next, let’s create some general page styles:
1 |
/* General
|
2 |
==================================== */
|
3 |
*, *:before, *:after { |
4 |
-moz-box-sizing: border-box; |
5 |
-webkit-box-sizing: border-box; |
6 |
box-sizing: border-box; |
7 |
}
|
8 |
|
9 |
body { |
10 |
background: #eaedf1; |
11 |
}
|
12 |
|
13 |
body, input, textarea { |
14 |
font: 1em/1.5 Arial, Helvetica, sans-serif; |
15 |
}
|
16 |
|
17 |
.container { |
18 |
max-width: 25em; |
19 |
margin: 2em auto; |
20 |
width: 95%; |
21 |
|
22 |
}
|
23 |
|
24 |
.title { |
25 |
font-size: 1.5em; |
26 |
padding: .5em 0; |
27 |
text-align: center; |
28 |
background: #323a45; |
29 |
color: white; |
30 |
border-radius: 5px 5px 0 0; |
31 |
}
|
You’ll notice we use Paul Irish’s suggested approach to the box model when styling forms: box-sizing: border-box;
.
Now we have something somewhat better, but it’s going to need some more work.



Creating Form List Styles
Let’s apply some styles to our form elements. These will make our form look more similar to Matt’s.
First, we will style the list elements that contain our form elements.
1 |
/* Form
|
2 |
==================================== */
|
3 |
.form ul { |
4 |
background: white; |
5 |
margin-bottom: 1em; |
6 |
}
|
7 |
|
8 |
.form li { |
9 |
border: 1px solid #ccc; |
10 |
border-bottom: 0; |
11 |
margin-bottom: 0px; |
12 |
position: relative; |
13 |
}
|
14 |
|
15 |
.form li:first-child { |
16 |
border-top: 0; |
17 |
}
|
18 |
|
19 |
.form li:last-child { |
20 |
border-bottom: 1px solid #ccc; |
21 |
}
|
Now we have all our form elements visually contained. You should have something like this:



Creating Form Element Styles
Let’s continue styling our form elements to match Matt’s design while also taking into account the accessibility constraints of the web.
Style the input fields as big block-level elements in the form:
1 |
label, input, textarea { |
2 |
display: block; |
3 |
border: 0; |
4 |
}
|
5 |
|
6 |
input, textarea { |
7 |
width: 100%; |
8 |
height: 100%; |
9 |
padding: 2.25em 1em 1em; |
10 |
outline: 0; |
11 |
}
|
12 |
|
13 |
textarea { |
14 |
height: 16em; |
15 |
resize: none; |
16 |
}
|
You should have something like this:



Then style the form <label>
elements to sit positioned about one-third of the way from the top of each input block.
1 |
label { |
2 |
font-size: .8125em; /* 13/16 */ |
3 |
position: absolute; |
4 |
top: 1.23em; |
5 |
left: 1.23em; |
6 |
color: #f1773b; |
7 |
opacity: 1; |
8 |
}
|
Note: did you notice the opacity
rule? We will be using that property (along with the top
property) to animate the <label>
element later on using JavaScript.
You should have something that’s starting to look a lot like Matt’s form design.



Next, need to style our form submit button.
1 |
input[type="submit"] { |
2 |
background: #f1773b; |
3 |
margin-bottom: 1em; |
4 |
color: white; |
5 |
border-radius: 3px; |
6 |
padding: .75em; |
7 |
-webkit-appearance: none; /* remove default browser <button> styling */ |
8 |
-webkit-transition: .333s ease -webkit-transform; |
9 |
transition: .333s ease transform; |
10 |
}
|
11 |
input[type="submit"]:hover { |
12 |
-webkit-transform: scale(1.025); |
13 |
transform: scale(1.025); |
14 |
cursor: pointer; |
15 |
}
|
16 |
input[type="submit"]:active { |
17 |
-webkit-transform: scale(.975); |
18 |
transform: scale(.975); |
19 |
}
|
Notice we used the attribute selector to target only the submit button. We added some basic styles along with a simple interaction on the :hover
and :active
states (older browsers that do not support CSS transforms
simply will not have a fancy interaction, but the form still works). You should now have something like this:



Our form has been styled in a way that is similar to Matt’s design but also tailored to appease the accessibility concerns of the web. Notice how, without any JavaScript, the form is still accessible with the form fields being displayed at all times. For users with older browsers that do not support the placeholder
attribute, they will still be able to see the form fields and ascertain what information is required of them.
In addition, the <input>
and <textarea></textarea>
elements cover the entire form field block, so the target area for each input is quite large and accessible.
For example, this is what the form would look like at this point in Internet Explorer 8:



Using JavaScript for a Progressively Enhanced Form
We shold now begin thinking about how to implement the interaction Matt created using JavaScript. We’ll accomplish this largely by adding and removing CSS classes.
You will notice right before the closing <body>
tag we put a link to our custom JavaScript file named scripts.js
. We can create that file now and tell the browser to run the code when the DOM is ready:
1 |
$(document).ready(function(){ |
2 |
// Our code here |
3 |
}); |
Checking for placeholder
support
In case you haven’t noticed, this interaction is highly dependent on placeholder support. The placeholder attribute is widely supported in modern browsers. Because our form interaction is so dependent on placeholder support, we will first test to see if the browser supports placeholder text. If it does, we will implement the form interaction. If it doesn’t (IE8 & IE9) we will simply provide the basic form without JavaScript interaction. Progressive enhancement for the win!
First, let’s use jQuery’s $.support()
to see if the browser supports placeholder text. This will set $.support.placeholder
to true or false, depending on the browser’s support for placeholder text.
1 |
// Test for placeholder support |
2 |
$.support.placeholder = (function(){ |
3 |
var i = document.createElement(’input’); |
4 |
return ’placeholder’ in i; |
5 |
})(); |
If placeholder text is supported, we can hide the <label>
elements on page load. As mentioned before, hiding the labels with JavaScript after the page loads ensures that browsers with JavaScript turned off (and those without placeholder support) can still use the form.
1 |
// Hide labels by default if placeholders are supported |
2 |
if($.support.placeholder) { |
3 |
$(’.form li’).each(function(){ |
4 |
$(this).addClass(’js-hide-label’); |
5 |
}); |
6 |
|
7 |
// Code for adding/removing classes here |
8 |
} |
Notice that we added a class to each list item named js-hide-label
. This is because, as per the interactions rules at the beginning of the tutorial, the default appearance of the form has the form field labels hidden. The js-hide-label
class will be applied to parent <li>
elements when the descendant <input>
element is empty of user content.
To aid in comprehension and code maintainability, we are prefixing the classes we add or remove with JavaScript with ’js-’. Let’s add that class to our style sheet and use it to hide all descendant label
elements from view. Remember how we were going to using the opacity
rule? This is where we use it to hide the <label>
elements:
1 |
.js-hide-label label { |
2 |
opacity: 0; |
3 |
top: 1.5em |
4 |
}
|
Note: The opacity
property is supported in all modern browsers. IE8 will not recognize it, but that’s ok because IE8 does not support placeholder attributes either, so we are not actually running the JavaScript to apply the class in IE8. Win-win!
A Note on Transitions
If you observe closely, Matt’s interaction design shows the form field labels not only appearing and disappearing, but doing so with a little up and down movement. Because our label elements are positioned absolutely, when we add a class that changes it’s top positioning (or left, right, or bottom) the browser can transition that effect. All we have to do is add a transition property to the label itself.
Let’s go back to our label
element in the CSS and add a transition property for the top
and opacity
properties:
1 |
label { |
2 |
-webkit-transition: .333s ease top, .333s ease opacity; |
3 |
transition: .333s ease top, .333s ease opacity; |
4 |
}
|
This allows the labels to not only appear and disappear smoothly, but to bobble up and down when becoming fully opaque or transparent, like so:



You should now have something like this when you load the page (in a modern browser of course).



Removing the Highlight Color
As mentioned before, we are adding and removing classes from the <li>
elements and targeting any children that need styling. At this point (on page load) we have added a class of js-hide-label
that hides all labels in the form. Now we need one more class for removing the highlight color from the <label>
elements:
1 |
.js-unhighlight-label label { |
2 |
color: #999 |
3 |
}
|
Adding Event Listeners
Now we have a form that is progressively enhanced and ready for some JavaScript interaction (in modern browsers) when the user begins interacting with the form.
Inside the placeholder if
statement we wrote above, let’s start adding and removing our js-
classes at the right moment. First, we will select our form elements and add an event listener on the blur
, focus
, and keyup
events (we use keyup
rather than keydown
or keypress
as those events will fire prematurely):
1 |
$(’.form li’).find(’input, textarea’).on(’keyup blur focus’, function(e){ |
2 |
|
3 |
// Cache our selectors |
4 |
var $this = $(this), |
5 |
$parent = $this.parent(); |
6 |
|
7 |
// Add or remove classes |
8 |
if (e.type == ’keyup’) { |
9 |
// keyup code here |
10 |
} |
11 |
else if (e.type == ’blur’) { |
12 |
// blur code here |
13 |
} |
14 |
else if (e.type == ’focus’) { |
15 |
// focus code here |
16 |
} |
17 |
}); |
Here is a brief explanation of what we are doing here:
- We select all list items that are part of our form
$(’.form li’)
. Then, inside that selection, we find all<input>
and<textarea>
fields.find(’input, textarea’)
. This ensures that the last input in our markup (the submit button) is not included in our selection. - We cached the selectors we plan on using. This is a good performance practice. Also, prefixing the variable name with ’$’ lets us know that that specific variable is a jQuery object.
- We combined the
blur
,focus
, andkeyup
events and simply check the event type usinge.type
to determine which classes we’ll be adding or removing at specific moments.
Coding on keyup
According to the interaction rules we laid out at the beginning which correspond to Matt’s design, when a user starts entering text (not when they focus on the field) we want to show the label.
So, using the keyup
event, every time the user enters a character we can check to see if the input field is blank (this code goes inside if(e.type == ’keyup’)
:
1 |
if( $this.val() == ’’ ) { |
2 |
$parent.addClass(’js-hide-label’); |
3 |
} else { |
4 |
$parent.removeClass(’js-hide-label’); |
5 |
} |
Notice our logic works like this:
- If the input’s value is blank, hide the label by adding the ’js-hide-label’ class.
- Otherwise (the input’s value is not blank), show the label by removing the ’js-hide-label’ class.
You should now have something that works like this when you enter or delete text from an input field:



Coding on blur
Now, according to our interaction rules (again), we know that when a user moves the focus from one input field to the next (blur
event), we should de-emphasize the color of the <label>
element depending on whether the user has actually entered anything into the field.
Inside the else if (e.type == ’blur’)
, we will add the following code:
1 |
if( $this.val() == ’’ ) { |
2 |
$parent.addClass(’js-hide-label’); |
3 |
} |
4 |
else { |
5 |
$parent.removeClass(’js-hide-label’).addClass(’js-unhighlight-label’); |
6 |
} |
Notice our logic works like this:
- If the input’s value was blank when the user removed focus, hide the label by applying the
js-hide-label
class. - Otherwise (the input’s value was not blank when the user removed focus) show the label by removing the class
js-hide-label
and de-emphasize the label’s color by adding the ’js-unhighlight-label’ class.
You should now have something that de-emphasizes the label’s color when you remove focus, like this:



Coding on focus
Last of all, we need to add a little logic for when a user focuses on an input. Following our interaction rules, let’s use the following JavaScript inside the else if (e.type == ’focus’)
section:
1 |
if( $this.val() !== ’’ ) { |
2 |
$parent.removeClass(’js-unhighlight-label’); |
3 |
} |
Our logic works like this:
- If the input’s value is not blank, remove the parent’s ’js-unhighlight-label’ class.
Now when a user focuses on a form field, if it’s not empty, the label will be emphasized with the highlight color, like so:



Bonus Points
There is a lot more we could do to this form, including the addition of client- and server-side validation. We could also create a few more classes for styling valid and invalid field values. For example, we could add styles to a class of ’js-error’ which would go on the parent <li>
element when the input’s value is invalid, like so:
1 |
.js-error { |
2 |
border-color: #f13b3b !important; /* override all cases */ |
3 |
} |
4 |
.js-error + li { |
5 |
border-top-color: #f13b3b; |
6 |
} |
7 |
.js-error label { |
8 |
color: #f13b3b; |
9 |
} |
These types of validation styles could make our form look something more like this:



However, this tutorial was meant to show how we could create an accessible, progressively enhanced form mimicking Matt’s design. And, I have to say, I think we have done pretty well.
Feel free to copy, modify, or improve this form in anyway you see fit in your own projects!
Useful Links
- http://floatlabel.com
- @floatlabel on Twitter; examples in the wild
- Brad Frost’s thoughts on the Floating Label Pattern