CSS-Plus
CSS-Plus
Play with web technologies

How to make the input placeholder more user friendly

September 22, 2011
Attention: This article is old and the content is outdated. I've left the article here for historical purposes.

I've always loved placeholder text for input fields. Not too long ago the only way to achieve this would be to create a special javascript function that enabled the desired functionality, but now it magically comes pre-built into HTML5. Incase you're wondering, placeholder text is the text within an input field that disappears once you click on it. It's often used in place of a label.

How is it not user friendly? tl;dr - Take me to the tutorial already

Placeholder text can be very helpful and can save a lot of page space while also being aesthetically pleasing. With this great feature, however, comes a problem: If the placeholder text is being used in place of a label, it can become very confusing when you focus on the field and the 'label' disappears.

It's important for users to know:

  • What field they are currently on
  • What field they have filled in

Typical input placeholder problem

Figure 1 - Standard input placeholder problem
Which input field am I on?
Based on the image above, it's impossible to tell what the first/focused field is. It is relatively simple to deduce it's either a 'username' or 'email' field. The only way to find out which field you're on would be to remove all the text in the field and blur (lose focus). I have personally been caught by this dozens and dozens of times and I find it very annoying.

One method that websites, such as Twitter, have been adopting is to have the placeholder text fade out slightly on focus, but only disappear once the user inputs some text. This is arguably the way that the HTML5 placeholder should work by default.

An improved version

Figure 2 - The Twitter input placeholder
  1. Normal Placeholder text
  2. Placeholder text fades out slightly on focus
  3. The input field is unknown once text has been added
  4. The title attribute is used to add information
The method that the Twitter login system uses is a big step up from the problem in fig.1, however the same problem still exists once the user has added text.

The title attribute has been used here so a user can see the placeholder text by hovering over the input field which is a great addition. Unfortunately in general, I still don't feel this is as very user friendly as it could be.

The solution

I would like all of the bonuses of both the placeholder method and the standard label method. I've decided there is one basic way to achieve this: Have either the label of the input field or an appropriate icon appear to the right of the field after the field has received focus.

So that's it, in this tutorial I'm going to show you how you can make a form with placeholder text that is semantic, user-friendly and degrades gracefully for legacy browsers.

The HTML

The following HTML is normal <form> markup. It's what we do with the CSS that really matters.
<form id="login">
    <ul>
        <li>
            <input id="email" name="email" placeholder="Your Email" title="Your Email" type="email" required />
            <label for="email">Your Email</label>
        </li>
        <li>
            <input id="password" name="password" placeholder="Your Password" title="Your Password" type="password" required />
            <label for="password">Your Password</label>
        </li>
        <li>
            <input id="submit" name="submit" type="submit" value="Login">
        </li>
    </ul>
</form>

The CSS

#login{font-size: 12px; margin: 0 auto; width: 700px;}
#login li{float: left; list-style: none; margin-left: 30px; position: relative;}
#login li:first-child{margin-left: 0;}

label{line-height: 40px; position: absolute; right: 120px; top: 0; bottom: 0; -moz-transition: 0.3s right ease; -ms-transition: 0.3s right ease; -o-transition: 0.3s right ease; -webkit-transition: 0.3s right ease; transition: 0.3s right ease; z-index: 0}

input{color: transparent; font-size: 12px; height: 35px; -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; -moz-transition: 0.3s all ease; -ms-transition: 0.3s all ease; -o-transition: 0.3s all ease; -webkit-transition: 0.3s all ease; transition: 0.3s all ease;}

input[type="email"], input[type="password"]{border: 1px solid #ccc; height: 35px; padding: 0 10px; width: 240px; position: relative; -moz-box-shadow: inset 0 0 10px rgba(0,0,0,.06); -webkit-box-shadow: inset 0 0 10px rgba(0,0,0,.06); box-shadow: inset 0 0 10px rgba(0,0,0,.06); z-index: 2;}

input[type="email"]{color: rgba(47,130,194,.8);} input[type="password"]{color: rgba(237,28,112,.8);}

/_ Placeholder _/ input[type="email"]:-moz-placeholder{color: rgba(47,130,194,.6);} input[type="email"]:-ms-input-placeholder{color: rgba(47,130,194,.6);} input[type="email"]::-webkit-input-placeholder{color: rgba(47,130,194,.6);}

input[type="password"]:-moz-placeholder{color: rgba(237,28,112,.6);} input[type="password"]:-ms-input-placeholder{color: rgba(237,28,112,.6);} input[type="password"]::-webkit-input-placeholder{color: rgba(237,28,112,.6);}

/_ Label _/ input[type="email"] + label{color: rgb(47,130,194);} input[type="password"] + label{color: rgb(237,28,112);}

input:focus + label{right: 10px;}

input[type="email"]:focus, input[type="password"]:focus{background-color: rgba(255,255,255,.8);}

/_ Submit _/ input[type="submit"]{ background-color: #333; background: -moz-linear-gradient(bottom, #333, #444); background: -ms-linear-gradient(bottom, #333, #444); background: -o-linear-gradient(bottom, #333, #444); background: -webkit-linear-gradient(bottom, #333, #444); background: linear-gradient(bottom, #333, #444); border: 1px solid #222; color: #fff; cursor: pointer; height: 35px; width: 110px; }

input[type="submit"]:hover{color: #ff6937;text-shadow: 0 0 1px rgba(255,255,255,.2);}

The CSS mostly consists of general styling, I'd say the most important two lines are:

input:focus + label{right: 10px;}
input[type="email"]:focus, input[type="password"]:focus{background-color: rgba(255,255,255,.8);}

So the label is absolutely placed behind the input field. On focus the label moves to the right while the input's background fades to a lower opacity. This gives the illusion of the label sliding right while fading in.

That's pretty much all there is to it. I think it's a neat little trick.

Let's give IE a bit of love

As always, IE spoils the party, but as always Modernizr is here to save the day. We can get the form to act almost identically (sans animations) on IE8 and functionally on IE 6 and 7. Firstly, make sure you've given either the <html> or the <body> tag IE specific styles. For example:
<!doctype html>
<!--[if lt IE 7 ]> <html class="no-js ie6 ie" lang="en"> <![endif]-->
<!--[if IE 7 ]>    <html class="no-js ie7 ie" lang="en"> <![endif]-->
<!--[if IE 8 ]>    <html class="no-js ie8 ie" lang="en"> <![endif]-->
<!--[if (gte IE 9)|!(IE)]><!--> <html class="no-js" lang="en"> <!--<![endif]-->
<head>
  <meta charset="utf-8">
  <script src="../../../js/libs/modernizr-2.0.6-min.js"></script>
Also, notice I've included Modernizr. I make use of Modernizr on pretty much every project I work on. It allows me to feature detect with javascript and I can make some pretty cool fallbacks with that.

Once we've got that set up we can easily start fixing up IE.

IE specific CSS

.ie input{line-height: 35px;}
.ie input[type="email"]{color: #2F82C2;}
.ie input[type="password"]{color: #ED1C70;}
.ie label{right: 10px;}

.ie input[type="email"]:focus, .ie input[type="password"]:focus{ background:transparent; -ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#80ffffff,endColorstr=#80ffffff)"; zoom: 1; } .ie7 label, .ie6 label{display: none;}

The CSS just makes things work in IE. Nothing special really. The weird -ms-filter is to add opacity to the background in IE.

Placeholder functionality fallback - jQuery with Modernizr

if(!Modernizr.input.placeholder) {
    $("input[placeholder]").each(function() {
        var placeholder = $(this).attr("placeholder");
    $(this).val(placeholder).focus(function() {
        if($(this).val() == placeholder) {
            $(this).val("")
        }
    }).blur(function() {
        if($(this).val() == "") {
            $(this).val(placeholder)
        }
    });
});

}

This little snippet does the following:

  1. Detects for the placeholder attribute support. If no support is found, it continues
  2. It then looks for all input elements with the placeholder attribute
  3. It then takes the placeholder value and puts that within the 'value' attribute
  4. When focus is given to the element the value is set to none
  5. When blurred, if the value attribute isn't nothing, it leaves the text alone
  6. If the value attribute is nothing, it replaces it with the placeholder text again

Foreseeable problems

The user can't see the text if the input is full of characters.
True story, but the opacity of the label is so low that it doesn't really interfere with the readability of the text itself. A way around this would be to add padding-right which covers the length of the label. The only downside to this would be the input field having to be very long.

In general I think this is fine, but if you're very worried about this, I'd say add padding-right to the label and use icons instead of text. This will save a lot of space.

Conclusion

I think it's a pretty solid technique that will leave your website visitors — or me at least — happier and less confused while logging in.
Demo