In HTML user-input forms, it is not uncommon to see text fields with “labels” as grayed-out text in the field itself which disappear when clicked. Unfortunately, it’s harder than it should be.

My search for “best practices” on this technique left me…wanting. Firstly, I wasn’t sure what to call it. Secondly, many implementations were riddled with problems, paramount of which was abominable degradation. I am no accessibility expert, but these solutions didn’t even try. After just a little thought, I came up with something better than any of them. (Not to say it’s the best, but I can’t find one better.) My goals were:

  • Unobtrusive
  • Graceful degradation (screen-readers and non-JS browsers can fall back on the labels or title attributes)
  • Uses all field attributes for their intended purposes
  • Places all responsibility/logic in one location, removing the need for controllers to treat certain values or fields specially

A possible draw-back is that users cannot submit a value that matches the field’s title. If that’s a real problem, you could probably add some more checks to hack around it. But how often is someone’s first name First?

My implementation uses >= jQuery 1.3. Since we’re on the Web anyway, I thought I’d throw in a working example below:

The HTML

<form id="form_field_label_example" action="" method="post">
  <p>
    <label for="first_name">First</label>
    <input id="first_name" name="first" title="First" type="text" />
    <label for="middle_name">Middle</label>
    <input id="middle_name" name="middle" title="Middle" type="text" />
    <label for="last">Last</label>
    <input id="last" name="last" title="Last" type="text" />
  </p>
</form>

The JavaScript

<script type="text/javascript">
  $(function() {
    auto_label("form#form_field_label_example input[title][type=text]")
  })

  function auto_label(str) {
    $(str).each(function() {
      // Hide the field's real label
      $('label[for=' + this.id + ']').hide()
      // Set the label text and color for blank fields
      if ( !this.value || this.value == this.title ) {
        this.value = this.title
        $(this).css('color', '#999')
      }

      // On focus of blank fields, clear the label text and reset the color
      $(this).focus(function() {
        if ( this.value == this.title ) {
          this.value = ''
          $(this).css('color', 'inherit')
        }
      })

      // On unfocus of blank fields, restore the label text and color
      $(this).blur(function() {
        if ( !this.value ) {
          this.value = this.title
          $(this).css('color', '#999')
        }
      })
    })

    // Clear label text when submitting form
    $(str).closest('form').submit(function() {
      $(str).each(function() {
        if ( this.title && this.value == this.title ) { this.value = '' }
      })
    })
  }
</script>