posted on:September 10, 2008

Using form labels as text field values


When designing you sometimes have limited space to put and display all of the form elements. Recently that happened to me and when I was trying to squeeze in a simple newsletter form to a 120px wide area (plus a limited height). I realized that some of the elements will have to go. The obvious solution was to get rid of the labels and put only the form text fields. How will the users know what are the text fields for? I will use value attributes and write the explanation in there, something like "Input your email here". Problem solved? Not quite. Why? Because I am a web standards freak 🙂

Take a look at the demo
| Download zip file

label to text field

The problem

Let’s rethink what I just did. I placed a sentence "Input your email here" as a text field value by adding it to the VALUE attribute. Why is that wrong? The VALUE attribute of the INPUT tag should be used as a default value of the text field, not as a text field’s description. The sentence I used is clearly a description and it should be used as a label (of course using LABEL tag). The correct way to use VALUE attribute for text fields is to input something meaningful, something that user might actually write himself (or herself). i.e. if you are logged in as member here on Css Globe and you wish to comment, you will notice that your email is set as a default value of an email text field in the comment form.
How will I find semantically correct way to place the labels (descriptions) into text field? JavaScript of course. It will help me to move stuff around without jeopardizing accessibility. Remember, the aim here is to have meaningful and accessible html code plus to have a usable form that fits the provided design.
Let’s begin with markup. It should look something like this:

<form id="contactForm" action="/" method="post">

<fieldset><legend>Contact Form</legend>
<p>
<label for="contact_name">Input your name here</label>
<input type="text" name="contact_name" id="contact_name" value="" size="30" />
</p>
<p>
<label for="contact_email">And email address please</label>
<input type="text" name="contact_email" id="contact_email" value="" size="30" />
</p>
<p>
<label for="contact_message">Send us a couple of words</label>
<textarea id="contact_message" name="contact_message"></textarea>
</p>
<p class="submit">
<button type="submit" title="Send your message">Send!</button>
</p>
</fieldset>

</form>

LABEL tags must have FOR attributes defined otherwise they don’t make much sense plus this script won’t work 🙂

The final design looks like this:

form design

Time to move it to the script. When dealing with this issue I came up with the script that automatically searches for LABEL tags, finds related INPUT (includes only text fields) based on a definition of FOR attributes and inputs the LABEL tag’s content into the text field using VALUE attribute. How’s that different from the straightforward non-semantic solution from the beginning of this article, you’ll say… Well, take a look at the form markup again. This form is accessible and semantically correct to begin with. JS disabled browsers will still have meaningful interpretation of this form.

Lets see the script already

This is and unobtrusive JavaScript code powered by fabulous jQuery. You don’t have to understand jQuery to use this form (but still this script requires it), I will try to explain each line. Here’s the entire thing:

this.label2value = function(){	

	var inactive = "inactive";
	var active = "active";
	var focused = "focused";
	
	$("label").each(function(){		
		obj = document.getElementById($(this).attr("for"));
		if(($(obj).attr("type") == "text") || (obj.tagName.toLowerCase() == "textarea")){			
			$(obj).addClass(inactive);			
			var text = $(this).text();
			$(this).css("display","none");			
			$(obj).val(text);
			$(obj).focus(function(){	
				$(this).addClass(focused);
				$(this).removeClass(inactive);
				$(this).removeClass(active);								  
				if($(this).val() == text) $(this).val("");
			});	
			$(obj).blur(function(){	
				$(this).removeClass(focused);													 
				if($(this).val() == "") {
					$(this).val(text);
					$(this).addClass(inactive);
				} else {
					$(this).addClass(active);		
				};				
			});				
		};	
	});		
};
$(document).ready(function(){	
	label2value();	
});

As you may notice from the code I have added css classes and attached some behavior to the fields to make a complete solution. Let’s take it step by step.

$(document).ready(function(){
	label2value();
});

This initiates the script called label2value (that’s our script here 🙂 ) on page load using jQuery’s $(document).ready function. First lines in our function:

var inactive = "inactive";
var active = "active";
var focused = "focused";

define the variables containing class names that we will use to style 3 states of the text field or text area:

  1. Inactive state – default state with no input from the user. With this state the label text inside the text field is used.
  2. Active state – when user provides some input and clicks away from the text field (on blur)
  3. Focused state – when user clicks on the field (on focus)

Classes should be styled to your preferences, in external css file or inside a STYLE tag on the document.
Moving on:

$("label").each(function(){
	obj = document.getElementById($(this).attr("for"));
	if(($(obj).attr("type") == "text") || (obj.tagName.toLowerCase() == "textarea")){

These lines basically select each LABEL tag and find matching text field or textarea based on the FOR attribute of the LABEL tag.

$(obj).addClass(inactive);
var text = $(this).text();
$(this).css("display","none");
$(obj).val(text);

Then it assigns default state class name to the text field, hides the label, gets the text from the label and puts it into text field.

$(obj).focus(function(){ 
	$(this).addClass(focused);
	$(this).removeClass(inactive);
	$(this).removeClass(active); 
	if($(this).val() == text) $(this).val("");
}); 

On focus function (when user clicks on the text field) changes the class name and if the user haven’t provided any text, it clears the field.

$(obj).blur(function(){ 
	$(this).removeClass(focused); 
	if($(this).val() == "") {
	$(this).val(text);
	$(this).addClass(inactive);
	} else {
	$(this).addClass(active); 
	}; 
});

On blur function (when user clicks out from of field) checks if user has provided some input and if so it assigns active class name. If user left the field blank, script switches back to default mode with initial text and initial (inactive) class name.

See this script in action or download the package.

Enjoyed the article?

Then don't miss our next one! Subscribe to our RSS feed or share it with your friends.

DeliciousStumbleUpon RedditSubscribe

Comments (13 Comments)

  1. dappleyard
    September 10, 2008

    Great article, an inventive way to getting around the problem. It's important not to pass things such as this off as unnecessary.
  2. Eric Fields
    September 10, 2008

    Great article and a proper semantic solution to a ubiquitous problem. This would be really simple in jQuery. Off the top of my head, and not without further tweaking and optimization, you could do this in jQuery by something like the following: $('form input[type="text"]').each(function(){ var theLabel = $(this).prev('label'); // Probably check to see if there's no value and then do the following $(this).attr('value',theLabel.html()); // Regardless, then you want to hide the label: theLabel.hide(); });
  3. cssglobe
    September 10, 2008

    yes, I wanted to make a start form the labels, firstly because I could then include textareas as well, secondly user could put labels before or after the text field, so targeting it with an ID seemed like a more "bulletproof" solution. Thanks for the comment!
  4. Nacho
    September 10, 2008

    Hi, cool article. I have a suggestion though. How about applying the class "inside" for those labels, and the js just applies that to labels having the .inside class? I think it would be better for people like me that don't know much js. Nacho.
  5. Dainis Graveris
    September 11, 2008

    Cool output. I really love those natural outcomes as notes, old papers etc. jQuery part is hardest one for me, so thanks for sharing the full code explaining it.
  6. Felipe Uribe
    October 7, 2008

    cool article!! one question yet, i might be off but you said it was for a newsletter, but as i understand javascript doesn't works the most of the times on email clients. so, can you use it or not? as i said i might be off but... thanks
  7. Gabe
    November 8, 2008

    I agree with Eric, seems over-engineered when jQuery can do it so much faster.
  8. Lush
    December 5, 2008

    Hi, apparently this nice idea is not working on Chrome. Anyone knows how this can be fixed? Thanks.
  9. Andrea
    January 9, 2009

    doesnt work in Firefox :(
  10. Zoran
    February 19, 2009

    Just another solution for the same thing... Following code should be applied to INPUT tag: <input name="Search" onfocus="if (this.value == 'Input text') this.value = '';" onblur="if (this.value == '') this.value = 'Input text';" value="Input text" type="text">
  11. Igor
    April 15, 2009

    /bow to last comment :)
  12. Jonas Wagner
    April 16, 2009

    In my opinion, the solution presented in this article is a step in the right direction... I cannot quite agree with the last two comments because I find it important to style inactive fields differently from active fields. Another issue is that when the form is submitted, the fields keep the values from their labels. This makes form validation quite a difficult task (your labels might be I18n'ized, etc...) I wrote some code which fixes the issue, available for some time at http://www.pastie.org/447497 The code uses Prototype instead of JQuery, but is otherwise very similar to the code presented here. It works for normal forms and for forms submitted using Ajax. Finally, the labels are styled only if they're of class "inside" (thanks Nacho).
  13. Kyle Rush
    May 1, 2009

    After using this script for a few weeks and really liking it, I ran into the problem stated above by Jonas. The inputs do not clear before submission, so the the label text gets submitted as the field's value. If you're already using jQuery, I've found this script to be just as good and without the clearing problem: http://github.com/alexrabarts/jquery-clearinginput/tree/master This is an otherwise great script. Thanks for sharing.

Sorry, the comment form is closed at this time.