SchmidtHappens

Fun With Form Labels

Let's be honest, forms labels are boring. I bet there are probably two ways you've done form labels: on top of the input field or to the left of the input field. Sure, you might get fancy with styling, but really that layout is pretty much the norm. Well, I say screw that! Let's explore ways we can spice this up.

First, a disclaimer. I will admit that the ideas for this article actually came from an experience I had with the Twitter login page. I like the approach that they took because it wasn't just a traditional use of the "placeholder" attribute. If you watch closely you will see that there is a slight animation in the way that the label disappears. It's subtle, but effective. Here, I will discuss ways you can accomplish this and also some alternatives that may work for your designs as well.

The Twitter Effect

So, looking into how Twitter accomplished the form effect I discovered a couple things. The first is that this uses CSS and a sprinkle of JavaScript. The other is that they are using a rather interesting approach to their markup. Let's look at the markup first.

<div>
  <input type='text' />
  <span class='holder'>Placeholder Text</span>
</div>

There are a few other attributes on the input element and the class names have been changed to protect the innocent, but this is pretty close to the actual code they are using. I have a problem with this though. Why they chose to use a span instead of the standard label element makes no sense to me. It's not semantic. There really is no reason for not using it. Plus, it doesn't degrade in browsers that won't understand the CSS.

Ok, so that was me on my soapbox and I can put it away now. For this article I will be using the following markup:

<div>
  <label for='someinputsid'>Label Text</label>
  <input id='someinputsid' type='text' />
</div>

Here are the styles that I apply to the form:

form {
  margin: 20px 0;
}

form,
form div {
  position: relative;
}

form div {
  margin-bottom: 10px;
}

form div input:not([type='submit']) {
  width: 250px;
  border-radius: 3px;
  border: 1px solid #888;
  -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .5);
}

form div label,
form div input:not([type='submit']) {
  height: 25px;
  line-height: 25px;
  margin: 0;
  padding: 5px;
  position: relative;
}

form div label {
  color: #777;
  line-height: 29px;
  padding-left: 8px;
  position: absolute;
  cursor: text;
}

And here is what I ended up with as a final product.

As you can see, I was able to keep a semantic structure to my HTML. This is important if the browser can't understand the CSS (say for example a screen-reader). Then, using a little CSS to style the input and label elements we have something that looks very close to our goal. Sadly, it's not very functional. If you try typing something into the fields you will quickly discover the problem.

The JavaScript Only Approach

This first example is almost a direct "copy" of the twitter form inputs. When you place your cursor in the field it will focus the input but the text will not disappear. Once you start to type something the label vanishes and your text is left behind. When the blur event occurs - your cursor leaves the input element - a check is done to see if the input field is blank. If it is, then the label is revealed again. Notice that I have also called the blur() method at the very end. I wanted to make sure I handled a situation where the value for the input was already set on page load.

The Code

$('#vanishExample input:not(:submit)').keypress(function () {
  $(this).prev().animate({ fontSize: 1, opacity: 0 }, 'fast');
}).blur(function () {
  var $this = $(this);
  if (!$this.val()) {
    $this.prev().animate({ fontSize: $this.css('font-size'), opacity: 1 }, 'fast')
  } else {
    $this.keypress();
  }
}).blur();

After working with the "vanishing" technique I realized there was a problem. It's one that I've encountered before and I view as a usability issue. Once you start typing in the field, the label disappears. We are expecting the user to remember what it is we are asking for. Unfortunately, with all of the distractions that we encounter on a daily basis it would be nice if we could have some indication of what it is we are supposed to be typing.

This next example uses a sliding label that will remain in view after the user begins to enter information into the field.

The Code

$('#slideExample input:not(:submit)').keypress(function () {
  var $this = $(this);
  // get the width of the input and add 10 pixels of padding
  $this.prev().animate({ marginLeft: (parseInt($this.css('width')) + 10) });
}).blur(function () {
  var $this = $(this);
  if (!$this.val()) {
    $this.prev().animate({ marginLeft: 0 });
  } else {
    $this.keypress();
  }
}).blur()

The CSS3 Way

Now that we have CSS3 we don't have to rely on JavaScript as much. In fact, we only really need to use it to manage the switching of the class name to reflect the current state of our input fields.

The first thing we will need to do is update our CSS to include the new CSS3 transition property.

...

form.transitions div label {
  ...
  -webkit-transition: all 0.4s ease;  /* Safari and Chrome */
  -moz-transition: all 0.4s ease;     /* Firefox 4+ */
  -o-transition: all 0.4s ease;       /* Opera */
  transition: all 0.4s ease;          /* Browsers that support non prefixed property */
}

...

We'll start with remaking the "vanish" form label. To facilitate this, we will need to add some additional CSS that will specify how the label should look. We will also need to add a class that can be used to trigger the effect with a pinch of JavaScript.

form div label.vanish {
  opacity: 0;
  font-size: 1px;
}

The JavaScript will be almost identical, except that we are now just toggling the css class for the label element.

$('#cssVanishExample input').keypress(function () {
  $(this).prev().addClass('vanish');
}).blur(function () {
  var $this = $(this);
  if (!$this.val()) {
    $this.prev().removeClass('vanish');
  } else {
    $this.keypress();
  }
}).blur();

Looks pretty good. Now onto the "slide" example. This one will require the same prep as the "vanish" example. For the CSS, I apply a position of absolute and then set the left CSS property to 260px.

form div label.slide {
  left: 260px; /* input width (250px) + 10px of padding */
}

And then update the JavaScript to use our new slide class.

$('#cssSlideExample input').keypress(function () {
  $(this).prev().addClass('slide');
}).blur(function () {
  var $this = $(this);
  if (!$this.val()) {
    $this.prev().removeClass('slide');
  } else {
    $this.keypress();
  }
}).blur();

Instant Awesome

I hope I've inspired you to think outside the box and motivated you to come up with your own unique way of mixing up the standard form layout. With advancements in CSS and JavaScript there really is no reason for not experimenting with new layout techniques. If you've created something spectacular please link to it in the comments. I love seeing what others are doing.

Something missing? Need more explanation? Let me know in the c-c-c-comments!

blog comments powered by Disqus