Awesome Inline Form Labels

How to create inline labels that don't suck, using CSS3 and some simple javascript.

Note: Demo works best in Safari 4.x and Chrome 5. In Firefox you won't see the label fading back (transition).

Hey there!

This demo is pretty old. Thanks to HTML5, there's now a much easier way to create placeholder text for text fields, and without any JavaScript! Just add the placeholder attribute to your input tags:

<input type="text" id="search" placeholder="Search here">

That's all you need! This works in IE10+, Firefox 4+, Chrome, Safari, and most mobile browsers.

This is a regular field with a background-image creating the shadow effect and a simple border change for the focus state.

This field has an inline label. It is structurally identical to the field above, but we've used negative margins (attached to class="inlined" on the label to move the field up and put the label behind it.

You can also use inline labels as example content for a field.

The CSS for Inline Labels

We won't touch on the CSS to create the inputs above - how you style your form elements is entirely up to you. What we're concerned with is how to do the inline label without making structural changes, and how to do the cool fading transitions (you see in Safari 4). There are a few key CSS lines that give us the positioning and effects we want.

In order for the effect to work we need to insure that the label falls behind the input. We need position: relative in order for the z-index to take effect.

This makes no difference for the standard display, but makes the inline label possible.

input.input-text {
  position: relative;
  z-index: 2;

label {
  position: relative;
  z-index: 1;

For our inlined label we need to move it right a bit and override the label text styling to match the input field. The real magic here is with the -webkit-transition property.

The syntax here tells the browser that when the opacity property changes, animate the changes over a 0.15s window and use a linear animation (as opposed to ease-in or ease-out).

label.inlined {
  padding-left: 6px;
  font-weight: normal;
  font-size: 12px;
  font-family: "Helvetica Neue";
  opacity: 0.75;
  -webkit-transition: opacity 0.15s linear;

And now the coup de grace. There are two tricks at work here, the first in the selector and the second in margining.

label.inlined + input.input-text tells the browser to apply properties to any input.input-text that is preceded (on a sibling level) by a label.inlined element.

Negative margining essentially moves the input up in front of the label (your label background will need to be transparent for this). Done and done.

label.inlined + input.input-text {
  margin-top: -22px;

And a Little Bit of JavaScript

In order for the label to fade and then disappear we need to apply classes at particular times. We'll use jQuery in this example, but the principle is the same for Prototype or straight JS.

Okay we lied, there's a little more CSS. These two classes will be applied when the input gains focus, and when the input receives text.

The extra -webkit-transition here means that when the user starts typing the label will instantly vanish, rather than fading off.

label.focus { opacity: 0.35; }
label.has-text { opacity: 0.0; -webkit-transition-duration: 0s; }

This is the javascript we need to selectively change classes on the label. There are four functions:

  • The first is an observer that helps us out with autocompletion - we detect if the browser filled in the text, and then clear the label.
  • When the input gains focus, move up to the label and apply the focus class.
  • When the user starts typing, apply the has-text class.
  • When the user shifts out of the field, check if it's empty: if so, remove the has-text class so the label will fade back in.
  $("label.inlined + input.input-text").each(function (type) {

    Event.observe(window, 'load', function () {
        if (!input.value.empty()) {
      }, 200);

    $(this).focus(function () {

    $(this).keypress(function () {

    $(this).blur(function () {
      if ($(this).val() == "") {

Copyright ZURB, freely available for distribution under the MIT license.

Startup playground

Log in with your ZURB ID

Log in with Google

Don't have a ZURB ID? Sign up

Forgot password?

Sign up for a ZURB ID

Sign up with Google

Already have a ZURB ID? Log in