Autopopulating text input fields with JavaScript

For both accessibility and usability reasons, all input fields and other form controls except buttons should have an associated label that clearly states what the purpose of the control is, or what kind of input the user is expected to fill it with.

Sometimes the visual design places restrictions on those labels, in some cases to the extent that there is no room for a label. Perhaps one of the more common examples of that is for site-wide search forms, where the graphic designer often will not accept a visible label. It's not an ideal situation, but it does happen, so we need to make the best of it. And since I've had to do this in a recent project I thought I'd describe the technique I ended up using.

Few people will argue against the need to explain to users what they are supposed to enter into text input fields. One common workaround when no label can be displayed is to put some placeholder text in the text field and let that act as the label.

This approach works reasonably well, but it burdens the user with having to clear the input before entering their own text, which can lead to frustration and mistakes. An approach that avoids that is using JavaScript to clear the input when it receives focus. Since that won't work when JavaScript support is missing, JavaScript should be used to insert the placeholder text as well.

Not having a visible label doesn't mean there can't be a label in the markup though. And you really need that label, since otherwise some users will have no clue what the field is there for. Apple's VoiceOver screen reader, for instance, announces "blank, edit text" when there is no label associated with a text input. However, if a label is there in the markup but visually hidden with CSS, VoiceOver will say "[Label text], edit text". Much better, right?

As a bonus, the hidden label will also help people browsing without support for JavaScript or CSS. Since the placeholder text is inserted with JavaScript I figured it makes sense to let the script hide the label as well.

And of course I wanted to do all of this unobtrusively, without any kludges like the inline onfocus and onblur event handlers that are often suggested when similar methods are described.


I'll use a simple search form as an example, though this is applicable to any text input fields. Here is the example markup:

  1. <form action="/search/">
  2. <div>
  3. <label for="searchtext" class="structural">Enter search text</label>
  4. <input type="text" name="searchtext" id="searchtext" title="Enter search text" class="populate">
  5. <input type="submit" value="Search">
  6. </div>
  7. </form>

There's nothing out of the ordinary here, but a number of the attributes I use here are important for this technique. First a bit about the label element's class attribute (which is in this markup snippet for illustrative purposes only – in reality it is put there by the script).


The label element has a class attribute with the value structural. This is a class name I tend to use for elements that should be hidden from people using a graphical browser with CSS support. The corresponding CSS is this:

  1. .structural {
  2. position:absolute;
  3. left:-9999px;
  4. }

This visually positions the label way outside the viewport, but it is still in the document flow and is not hidden from screen readers. As I mentioned above, this class will be added with the script and won't be in the actual markup.

The JavaScript

With the label hidden to please the graphic designer, let's look at the attributes for the input element. The title attribute contains the text that the script will put in the text field. You could argue that the text in the label element would be just as appropriate, and you may be right. In this case the text is the same as that of the input element's title attribute, so using the label text would trim the markup. I decided to use the title attribute anyway to have the flexibility of not having to use exactly the same text as in the label.

The script looks like this (with the utility functions getElementsByClassName() and addEvent() removed for brevity):

  1. var autoPopulate = {
  2. sInputClass:'populate', // Class name for the input elements to autopopulate
  3. sHiddenClass:'structural', // Class name that gets assigned to hidden label elements
  4. bHideLabels:true, // If true, labels are hidden
  5. init:function() {
  6. // Check for DOM support
  7. if (!document.getElementById || !document.createTextNode) {return;}
  8. // Find all input elements with the given className
  9. var arrInputs = autoPopulate.getElementsByClassName(document, 'input', autoPopulate.sInputClass);
  10. var iInputs = arrInputs.length;
  11. var oInput;
  12. // Loop through the found input elements
  13. for (var i=0; i<iInputs; i++) {
  14. oInput = arrInputs[i];
  15. // Make sure it's a text input. If not, skip to the next input.
  16. if (oInput.type != 'text') { continue; }
  17. // Hide the input's label
  18. if (autoPopulate.bHideLabels) { autoPopulate.hideLabel(; }
  19. // If value is empty and title is not, assign title to value
  20. if ((oInput.value == '') && (oInput.title != '')) { oInput.value = oInput.title; }
  21. // Add event handlers for focus and blur
  22. autoPopulate.addEvent(oInput, 'focus', function() {
  23. // If value and title are equal on focus, clear value
  24. if (this.value == this.title) {
  25. this.value = '';
  26. // Make input caret visible in IE
  28. }
  29. });
  30. autoPopulate.addEvent(oInput, 'blur', function() {
  31. // If the field is empty on blur, assign title to value
  32. if (!this.value.length) { this.value = this.title; }
  33. });
  34. }
  35. },
  36. hideLabel:function(sId) {
  37. // Find all label elements
  38. var arrLabels = document.getElementsByTagName('label');
  39. var iLabels = arrLabels.length;
  40. var oLabel;
  41. // Loop through the found label elements
  42. for (var i=0; i<iLabels; i++) {
  43. oLabel = arrLabels[i];
  44. // If the value of the label's for attribute equals the input element's id, hide the label
  45. if (oLabel.htmlFor == sId) {
  46. oLabel.className = oLabel.className + ' ' + autoPopulate.sHiddenClass;
  47. }
  48. }
  49. }
  50. };

The extensive comments I have written to explain what is going on make the script look a lot bigger than it really is. If you use a library like DOM Assistant or jQuery you can cut down on the length of this script a lot more. I like keeping demo scripts library agnostic though, so I'll leave that as an exercise for the reader.

The full script, available in autopopulate.js, contains the getElementsByClassName() and addEvent() utility functions, so if you want to you can use it as is. If you're already using other functions that do the same thing I'd recommend using those instead.

I've made a small demo form where you can see this in action. With JavaScript enabled, the label element is hidden and the value of the input element's title attribute is copied to the value attribute. If you disable JavaScript and reload the page, the label is displayed above the text input, which is left empty.

You may notice that the label is displayed briefly before the script hides it. This can be circumvented by running the script when the DOM is ready instead of on window.load, but how to do that is beyond the scope of this demo.

I definitely prefer displaying form labels, but if it simply is not possible due to design or space constraints, I think this is a reasonable workaround.

Posted on October 17, 2007 in JavaScript, Accessibility, Usability