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.
The HTML
I’ll use a simple search form as an example, though this is applicable to any text input fields. Here is the example markup:
<form action="/search/"><div><label for="searchtext" class="structural">Enter search text</label><input type="text" name="searchtext" id="searchtext" title="Enter search text" class="populate"><input type="submit" value="Search"></div></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 CSS
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:
.structural {position:absolute;left:-9999px;}
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):
var autoPopulate = {sInputClass:'populate', // Class name for the input elements to autopopulatesHiddenClass:'structural', // Class name that gets assigned to hidden label elementsbHideLabels:true, // If true, labels are hiddeninit:function() {// Check for DOM supportif (!document.getElementById || !document.createTextNode) {return;}// Find all input elements with the given classNamevar arrInputs = autoPopulate.getElementsByClassName(document, 'input', autoPopulate.sInputClass);var iInputs = arrInputs.length;var oInput;// Loop through the found input elementsfor (var i=0; i<iInputs; i++) {oInput = arrInputs[i];// Make sure it's a text input. If not, skip to the next input.if (oInput.type != 'text') { continue; }// Hide the input's labelif (autoPopulate.bHideLabels) { autoPopulate.hideLabel(oInput.id); }// If value is empty and title is not, assign title to valueif ((oInput.value == '') && (oInput.title != '')) { oInput.value = oInput.title; }// Add event handlers for focus and blurautoPopulate.addEvent(oInput, 'focus', function() {// If value and title are equal on focus, clear valueif (this.value == this.title) {this.value = '';// Make input caret visible in IEthis.select();}});autoPopulate.addEvent(oInput, 'blur', function() {// If the field is empty on blur, assign title to valueif (!this.value.length) { this.value = this.title; }});}},hideLabel:function(sId) {// Find all label elementsvar arrLabels = document.getElementsByTagName('label');var iLabels = arrLabels.length;var oLabel;// Loop through the found label elementsfor (var i=0; i<iLabels; i++) {oLabel = arrLabels[i];// If the value of the label's for attribute equals the input element's id, hide the labelif (oLabel.htmlFor == sId) {oLabel.className = oLabel.className + ' ' + autoPopulate.sHiddenClass;}}}};
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.
- Previous post: Videos of people using assistive technology
- Next post: Adobe Spry 1.6 improves standards support, adds progressive enhancement
Information, sponsorship, and externals
About the author
Roger Johansson is a Swedish web professional specialising in web standards, accessibility, and usability. More about me and this site.
Latest articles
- Validation statistics from Nikita the Spider Comments off
- An analysis of the sites crawled by the bulk validation tool Nikita the Spider during March 2008.
- Authentic Jobs API and Affiliates program Comments off
- The Authentic Jobs job listing service now has a public API and an affiliate program.
- What does Acid3 mean to you and me? Comments off
- Opera and Apple have announced that their web browsers pass the Acid3 Browser Test, but how will that help web designers and developers?
- Designing Web Navigation (Book review) Comments off
- Learn the fundamentals of navigation design and design better navigation systems for large and small sites as well as for web based applications.
- DOMAssistant bundle for TextMate Comments off
- To save keystrokes and speed up development I have created a DOMAssistant bundle for TextMate.
- First impressions of Internet Explorer 8 Beta 1 Comments off
- My impressions after trying out Internet Explorer 8 Beta 1 for a couple of days.









Comments
How timely, I was just about to write some code to do exactly this.
One issue I always have when hiding content with JavaScript is the slight delay between the HTML loading and the JS loading/executing which results in the text being visible briefly and then the entire page shifting as it is hidden. This becomes more of an issue when dealing with larger areas of content that are hidden.
Just wondering if you had any tricks to work around this.
Definitely a helpful snippet.
@Chris: Roger does give a tip for working around the flicker. Read the last paragraph on the demo page.
It's definitely always a good idea unobtrusive JavaScript to have the mindset that JavaScript should be used to enhance the page, rather than provide base functionality. This snippet definitely does that. Thanks Roger!
Oops, I clicked the link to the demo form and didn't read anything after. I shall now go do some research.
Why...
instead of...
Especially since this would avoid the...
Or do screen readers not read items where display is set to none in the CSS?
I've been marking up my forms with
<fieldset>and<legend>and hiding the legend via display:none, under the assumption that screen readers ignored CSS. Hrm....Nice technique Roger. I think I might actually prefer this method to the method discussed at A List Apart, because it's always tough to get the labels looking just right over the input with that method. On the other hand, there's already a jquery plugin for that method. It could be days before someone writes one for yours. :)
You're a genius. :) I'll definitely make myself a JQuery version for some form rewriting which is on my todo-list.
I have to agree with Jim D above. As I was reading this, I had the exact same question.
Chris:
You can avoid that by running the script when the DOM is ready. Most libraries have functionality for that, or you can write your own. Google for DOM ready to get many different implementations.
Jim D:
That's exactly the problem. Screen readers in general do not ignore CSS since they run on top of a browser.
Scott:
:-)
That's a beautifully accessible method, but where I work, flashes of un-script-styled content are unacceptable. I'm not aware of the current state of screen readers--is media="reader" honored?
(In my experience, DOMContentLoaded still isn't instantaneous for large pages.)
Really strange — i did same things three days ago for my new site, but with label text inside inputs and some special onfocus/onblur manipulation (jQuery):
http://pepelsbey.net/pro/label/
…plus onsubmit action to prevent sending default values to server.
What do you think?
You could create the css styles for .structural using javascript and always apply the class="structural" in the html (instead of applying it dynamically). That would avoid the flicker issue as long as your javascript comes before the element on the page.
Just as an exercise, this is how you'd write this with jQuery:
As an aside, jQuery will execute this when the DOM loads rather than the page, so you shouldn't see the label at all.
Also, I've not tested this, but it should work!
Just a quick note to enforce Eric's comment above. In certain situations DOM ready isn't fast enough to prevent the flicker either. It won't be necessary in all situations but where it is using JS to apply styling upfront is the most robust way to ensure no flicker occurs.
This is one of my favorite little tricks. To aid in making search fields in particular look more "search like" to please the designers I've also often flipped from input to the non-standard search field while doing the label-initial-text replacement where appropriate.
Of course you can also go all out and style the field accordingly to emulate that same look in browsers that don't support the search input type and even emulate some of the behavior of the search field: providing a clear button, clearing on esc.
Anyway, nice way to enhance a form while maintaining accessibility, glad to see it written up so clearly.
Braden:
Not as far as I know.
pepelsbey: I didn't look at your implementation in detail, but it seems quite similar. I'd move the label elements before their inputs in the source though to make the form usable with JS off. You don't need the tabindex attribute either - the inputs are already in logical order in the markup.
seb:
That's only a partial solution - you'd need to handle blur as well :-).
Ed:
I've been working on some pretty large and "heavy" stuff lately and have not come across that yet. Any idea of what specifically may cause that?
I think this is a great idea! Most web developers tend to get content when "losing" the battle with the designer, and end up not going the whole nine yards.
This is a great example how you can create good accessible code and then enhance it with JavaScript!
Didn't fully read through exactly what the script does... Here's a fully working version in jQuery, also adding a class "inputLabel" which can be used to make the label text grey...
The Javascript will only run once all linked script files are loaded into the browser. So if you have a 50k javascript library on the page, the will have to wait which may cause a delay.
Placing scripts at the bottom of the page rather than the top is the natural way to achieve domready firing
Brilliant idea - much better than not having a label and using a default input value.
Personally, I'm not against JavaScript changing pages after the page has loaded (within reason, anyway). That's the way progressive enhancement should work - the page is usable before the download has completed.
I think it's only noticeable on your demo because there's little else on the page. It wouldn't be so bad on a normal web page.
Why use the title attribute when the label text already exists?
Here's my take on the hidden label technique - you can never have too many ways to skin a cat. :)
Matthew:As the author said in the article he toyed with the idea but went with the title attribute for flexibility.
Pete: While there are advantages of placing JS at the bottom of the page, achieving DOMready is not one of them. You're correct that JavaScript blocks the page display. That's why it's good for scripts that are going to change the look of the page to be in the head and call DOMready because then they're code is loaded and will fire once the DOM is fully available. In this example placing the scripts at the bottom would mean that the code would show the label and then once it hits the script tag it will fire the event and cause the labels to be applied the class to hide them.
About the hiding technique, while it is good there may be issues using it with older versions of Opera and Safari. If true, using off-top may be preferred, but it seems negligible at this point.
Anything that prevents the entire page from being parsed all at once by the browser.
The most obvious example is a javascript include in the middle of your body. The DOM won't be ready until that js file has been downloaded, but the browser will have already parsed any html before that include. Here's a quick example.
I'd just like to note that the way you add the classname to the label causes problems in opera when (like in this case) the element doesn't yet have a classname. The leading space confuses opera (not sure about newer versions) and will thus not hide the label.
Thanks for the interesting demos, Eric. The Javascript style creation is really clever.
nicely done. ages ago, i wrote a little script for form prepopulation myself, but it's definitely much more basic than this.
Cool, I just wrote a jQuery-version a few weeks ago for a freelance thing but that uses the input's alt-attribute rather than its title-attribute. I actually skipped the label on that project because my hopes were that the alt-attribute would be read by a screen-reader. Anyone know if that's true? If screen-readers read out the alt-attribute, could that be a substitution for a label in those cases were the designer doesn't want them and it's obvious what the form is for if you can see it?
Although it isn't helpful in this case, you want to 'hide' the label irrespective of javascript support, you can put any css styles that you want if there's javascript support into a separate stylesheet and use a document.write in the head to link to it. This avoids waiting for the document to load before changing the look.
Andreas:
The only form element that can take an
altattribute is<input type="image">. You can use thetitleattribute for all form elements though, and some (but not all) screen readers will read that if they can't find a label. You really should always add a proper label. Hide it with CSS if you must, but put it in the source code.Ok, thanks for that. When I've used the alt-attribute in other types of inputs the validator has never complained. Is it really invalid or just not proper use? I'll change my jQuery-snippet so it uses the title-attribute instead. Cheers.
Roger, you should think of swaping your addEvent method for the rock solid one, which will help you avoid memory leaks in IE.
http://www.dustindiaz.com/rock-solid-addevent/
Andreas: As I understand it, the
altattribute slips through validation forinputelements because the validator doesn't make a special case fortype="image". For the same reason, the validator does not flag<input type="image">as an error despite it having noaltattribute.Either way it's meaningless since
altis meant as an alternative for an image or other graphical object. So for your purposes using thetitleattribute is better.Here is a slightly easier to read and cleaner version of this functionality written with help of Prototype. It also prevents from submitting the label text as an input value to the server. Enjoy.
Nicely done script. I'm also working on the basics of jQuery. I tried substituting the javascript with Seb's code, but nothing happened. Apparently additional code is needed? There is a jQuery watermark plugin, but I'd rather understand how it's done. Thanks.
I find it most entertaining how you get the predictable "this is how you can do it with xyz library" comments. It then becomes obvious that the point of Rogers article was completely missed. So far I counted three versions using jQuery, and one with Prototype. Roger is teaching "JavaScript." Not a library, pure JavaScript.
<humor>
Oh, by the way, here's how you would do this in my brand new library to come out...
Beat that!
</humor>
Isn't using both the label and title a little redundant?
I've never used a screen reader but I would guess that hearing repetitive content like this (even with subtle dissimilarity) would be more of an annoyance than an assistance?
That being said I'll definitely be using this (with the aforementioned adjustment) on my sites going forward. Great balance of proper xhtml tagging, usability, and unobtrusiveness. Thanks!
To expand on Seb's Post (#13), if you want to have the text re-populate when the focus is changed...
Has anyone figured out how to clear the fields before submission if the default value wasn't replaced? (Using the original code of course...)
Sorry, comments are closed for this post.