Creating a form with labels inside text fields using jQuery

It’s common to see forms that have a label displayed inside text fields which then disappear when you click into the field. Let’s go through an example for a login form that demonstrates a method for doing this.


First, start with a simple HTML form:

<form action="" method="post" class="login">
<ul>
	<li>
		<div class="title">Login</div>
	</li>
	<li>
		<label for="username">Username</label>
		<input id="username" type="text">
	</li>
	<li>
		<label for="password">Password</label>
		<input id="password" type="password">
	</li>
	<li>
		<button type="submit">Login</button>
	</li>
</ul>
</form>

Next let’s start styling up the form.

/* Create a bordered box for the form */
form.login {
	background-color:#eee;
	width:300px;
	padding:10px 20px;
	border:5px solid #ddd;
}
 
/* Set the font for all of the elements */
form.login,
form.login input,
form.login button {
	font-family: Helvetica, Arial;
	font-size:18px;
}
 
/* Make our title a bit bigger */
form.login div.title {
	font-size:24px;
	font-weight:bold;
	margin-bottom:10px;
}
 
/* Remove the bullets and padding from our list */
form.login ul {
	list-style-type:none;
	padding:0;
	margin:0;
}
 
/* Give our input fields a fixed width and a bit of padding */
form.login input {
	width:280px;
	padding:5px;
	margin-bottom:10px;
}

For the next step we want to have our labels displayed over the top of our input fields. So a bit of extra CSS to do that.

/* Make each field container relative.
This lets us position the label absolutely inside it. */
form.login ul li {
	position:relative;
}
 
/* Position the labels inside our input fields. */
form.login label {
	position:absolute;
	top:8px;
	left:9px;
	color:#aaa;
}

Lastly we need to have the labels disappear when we start editing a text field and reappear again if we leave the text field without entering a value.

We will use the jQuery focus() function to handle entering a text field and the blur() function to handle when leaving a field. We’ll also hide the labels for fields that have a pre-populated value.

$(document).ready(function(){
 
	// Find each of our input fields
	var fields = $("form.login input");
 
	// If a field gets focus then hide the label
	// (which is the previous element in the DOM).
	fields.focus(function(){
		$(this).prev().hide();
	});
 
	// If a field loses focus and nothing has
	// been entered in the field then show the label.
	fields.blur(function(){
		if (!this.value) {
			$(this).prev().show();
		}
	});
 
	// If the form is pre-populated with some values
	// then immediately hide the corresponding labels. 
	fields.each(function(){
		if (this.value) {
			$(this).prev().hide();
		}
	});
 
});

However jQuery supports function chaining, so perhaps a nicer way to write this may be:

$(document).ready(function(){
 
	$("form.login input")
		.each(function(){
			if (this.value) {
				$(this).prev().hide();
			}
		})
		.focus(function(){
			$(this).prev().hide();
		})
		.blur(function(){
			if (!this.value) {
				$(this).prev().show();
			}
		});
});

EDIT:

Dan G. Switzer, II provided a slightly more succinct version of the jQuery code:

$(document).ready(function(){
 
	$("form.login input")
		.bind("focus.labelFx", function(){
			$(this).prev().hide();
		})
		.bind("blur.labelFx", function(){
			$(this).prev()[!this.value ? "show" : "hide"]();
		})
		.trigger("blur.labelFx");
 
});
This entry was posted in jQuery and tagged , , , , . Bookmark the permalink. Both comments and trackbacks are currently closed.

18 Comments

  1. Posted January 7, 2011 at 3:20 pm | Permalink

    @Kevan:

    Instead of using the each() method, you can simplify the code by doing:

    $(document).ready(function(){

    $(“form.login input”)
    .bind(“focus.labelFx”, function(){
    $(this).prev().hide();
    })
    .bind(“blur.labelFx”, function(){
    // hide or show the label based on whether we have values in the field
    $(this).prev()[!this.value ? "show" : "hide"]();
    })
    .trigger(“blur.labelFx”);

    });

    What I did was change the blur() event to hide or show the label based upon whether or not the value is present. We need to make sure to explicitly use hide() if there’s a value in there, because I use the trigger() method to call the blur() event on each field after initialization. This makes sure that all your pre-filled in values get processed correctly.

    Also, you’ll notice I also gave namespaces to the event. That was so I could explicitly trigger just the blur.labelFx. Without namespaces, calling trigger(“blur”) would run all blur events and if you end up attaching multiple behaviors to the fields you really don’t want to re-run those behaviors more than you need to. The namespace gives you a way to trigger only the events you care about.

  2. Posted January 7, 2011 at 8:06 pm | Permalink

    @Dan

    That’s outstanding! Thank you.

  3. ben
    Posted February 9, 2011 at 11:00 am | Permalink

    hello.. I’m new to this.. hope you can help me with this.. i’m using “Using form labels as text field values” jquery. where can I set the email receiver? when the comment or message will automatically send to the your mail?..

    thanks

  4. Posted February 9, 2011 at 10:52 pm | Permalink

    @ben, to send an email from a web form you’ll need to use a server language such as PHP or ColdFusion. Here’s a Google search that might help get you started:

    http://www.google.com/search?q=form+send+email+php

  5. Benjy Freedman
    Posted February 16, 2011 at 11:29 pm | Permalink

    Sorry to sound stupid, but I have two questions.
    Firstly, do you have to create the username and passwords as a list. The reason I ask is that if you were doing this for a whole form, I wonder if there’s a way to create a div or something for all fields in the form and then refer to the div.
    Secondly, where exactly in your code did you put the javascript – I can’t seem to get it to work on mine.
    Thanks!

  6. Posted February 16, 2011 at 11:45 pm | Permalink

    @Benjy, the form fields can definitely be marked up different ways, but you will most likely need to have a separate container for each label/formfield pair (such as a DIV or an LI, as in my example). I had the JavaScript code up within the head of the page. You can see a live demo over here: http://www.jzoo.com/demo/login-form/

  7. Benjy Freedman
    Posted February 17, 2011 at 7:24 pm | Permalink

    Ok, thanks for that. I sort of have it working, but now have a different problem.
    I can only ‘see’ the username field.
    Below is my various bits of code.

    In main index file:

    Username

    Password

    From css file:
    #LoginPage {
    position:relative;
    float:left;
    margin-right:3px;
    }
    #uname {
    position:relative;
    }
    #pword {
    position:relative;
    }
    form.login label {
    position:absolute;
    top:3px;
    left:10px;
    color:#aaa;
    }

    Any ideas?
    Thanks!

  8. Posted February 18, 2011 at 6:14 am | Permalink

    @Benjy, sorry looks like wordpress ate your html tags. Feel free to repost. To get it to display properly in the comment wrap your html code with a pre tag:

    <pre lang="html4strict">

    And you can wrap your CSS code with

    <pre lang="css">
  9. Posted February 21, 2011 at 1:16 pm | Permalink

    thanks needed this, but it my case it did not work correctly due to the prev() function.

    because I had other dom elements that were after the label and before the input, i had to use sibling(“label”)
    i.e. replace all instances of prev() with sibling("label")

  10. Posted February 21, 2011 at 1:22 pm | Permalink

    another update i had to do was to refine the selector a bit.

    instead of input i filtered it further to limit the selector to text input types only.

    $(“form.login input[type=text]“)

  11. Posted February 21, 2011 at 6:54 pm | Permalink

    @johnny, thanks for the note.

  12. Posted March 1, 2011 at 12:29 pm | Permalink

    Nice writeup. Whenever I need to do something like this, I tend to wrap the label and input in a fieldset.

    One thing worth adding is handling users without JavaScript turned on as otherwise the label will appear in the text and it will look very confusing. To do so you can add the following squirt of jQuery:


    /* Only apply the positioning style if JS is on */
    $('form.login label').addClass('labels-inside-inputs');

    Then change the CSS selector to be:

    form.login label.labels-inside-inputs { ... }

  13. Posted March 1, 2011 at 7:18 pm | Permalink

    @Rich, great tip, thanks!

  14. ed
    Posted March 13, 2011 at 5:39 pm | Permalink

    I’m trying to get the email address above my label to go inside my label…my site i’m working on is http://www.greatcontradictions.com/

    How do I get the label to display email address inside the label?

    Thanks in advance.

  15. Posted March 14, 2011 at 3:44 am | Permalink

    @ed, you’ll need to set your container div to have a position:relative , then you can set your label to have an position:absolute and set your top and left values to position the label within the text box. For example:

    <div class="mc-field-group" style="position:relative">
    <label for="mce-EMAIL" style="position:absolute;top:8px;left:10px;">Email Address </label>
    <input type="text" value="" name="EMAIL" class="required email" id="mce-EMAIL">
    </div>
  16. Lisa Rose
    Posted April 21, 2012 at 9:11 pm | Permalink

    Hi!

    Thanks for the great A-B-C instructions for this plugin! I have a slight problem, tho. When you click in one input field, the other labels move position. The address is

    http://dogwood.nada.lisareisman.com/contact.php

    so you can see what I’m talking about. I used absolute positing with ID’s for each label, they are not a class. Can you suggest a remedy for this? I would greatly appreciate it!

    Have a good one!

  17. Alex
    Posted May 9, 2012 at 4:40 pm | Permalink

    A small issue occurs following this guide – the absolutely positioned label on top of the field doesn’t propagate the click to the field, so you have to click on the white space to engage the field.

    $(“… label”).click(function(){
    $(this).next().focus();
    });

    and showing a text cursor with CSS over the label would solve the problem. Cheers!

  18. Posted May 23, 2012 at 9:26 pm | Permalink

    Thank for this!

    By the way, you also need a change handler in case a user fill in the form using the Browser’s autofill settings – selecting an autofill in one field could automatically fill all the rest of the fields, without any focus/blur events being fired. I got around that by doing this:

    .bind(“change.labelFx”, function(){
    $(this).trigger(“blur.labelFx”);
    })

One Trackback

  1. [...] solution is to either use a top-aligned label, or add the form label as a text-field value. The latter requires less vertical real estate, but can be a little annoying if the field [...]