Input Prompt Text: A Better Way

It’s a very cool feature to have a form field that has prompt text such as Enter search keywords… right inside the input box, itself. It looks good, it makes sense to users, and it can save a lot of real estate in your design by negating the need for field labels. The problem, however, is that there are about one hundred ways to implement prompt text, and ninety-nine of them are wrong. Let’s look at this thing from all angles and come up with a fantastically simple and reliable way to make this work.

What is input prompt text?

You’re probably familiar with the concept, even if you don’t know what I’m talking about. Here’s an example:

The prompt text appears inside the form field as soon as the page loads, so users immediately know what it’s for. Simple, right?

Why it Doesn’t Work

There are a number of problems you’ll encounter while implementing prompt text into your forms. Watch out for these caveats when you’re developing your own solution.

  1. Input validation — if someone submits the form without first removing the prompt text, your prompt text is submitted in lieu of real data. Fixing this is a pain. Avoiding this entirely is recommended.
  2. Prompt style — it’s best to style the prompt text so that it doesn’t look like real form data. Creativity is a virtue, but generally web users will expect light (gray) text and italics. This can be problematic because you’ll have to swap the input style back and forth using JavaScript.
  3. Losing focus — when users focus on a form field, don’t type anything, and then click somewhere else, you should always add the prompt text back into the input box. Otherwise, users could miss the intent of the form field entirely. Again, you’ll have to do this with JavaScript, which can be a little tricky.
  4. Progressive enhancement — always make sure that users without JavaScript can still understand and interact with your form fields. This is progressive enhancement at its finest.

The Solution

Almost everything related to the problems listed above originates from one basic fact: you’re trying to create both a field and a label using a single HTML element. When you take a step back and think about that, it really doesn’t make much sense, does it? The solution lies in separating the form field from the label entirely. We’ll use a little bit of jQuery to create an elegant solution that dynamically creates these labels and places them over our form fields. Because we’re creating two separate elements, we can use CSS to style them independently. Perfect!

The jQuery:

$(document).ready(function(){
  $('input[type=text][title],input[type=password][title],textarea[title]').each(function(i){
    $(this).addClass('input-prompt-' + i);
    var promptSpan = $('<span class="input-prompt"/>');
    $(promptSpan).attr('id', 'input-prompt-' + i);
    $(promptSpan).append($(this).attr('title'));
    $(promptSpan).click(function(){
      $(this).hide();
      $('.' + $(this).attr('id')).focus();
    });
    if($(this).val() != ''){
      $(promptSpan).hide();
    }
    $(this).before(promptSpan);
    $(this).focus(function(){
      $('#input-prompt-' + i).hide();
    });
    $(this).blur(function(){
      if($(this).val() == ''){
        $('#input-prompt-' + i).show();
      }
    });
  });
});

The CSS:

.input-prompt {
  position: absolute;
  font-style: italic;
  color: #aaa;
  margin: 0.2em 0 0 0.5em;
}

The HTML:

<input type="text" title="Enter search keywords..." />

Basically, this script finds any <input> tags that have a title attribute (i.e. <input title="Enter search keywords..." />). For each of these form fields, it takes the title and creates a little <span> tag next to it. The CSS positions the <span> tag so that it appears on top of the form field. The rest is just a little bit of scripting that makes sure to hide and show the labels based on what the user is doing with the input box.

The Result

Here is a demo of the code shown above:


Users without JavaScript enabled will see the normal title tool tips when they hover their mouse cursor over the form field. Please note that you’ll probably have to adjust the margin a bit in the CSS to make sure the labels fit the size of your input boxes. For more information on jQuery and all the great things it can do, visit jQuery.com.

41 comments

  1. [...] Input Prompt Text: A Better Way – Kyle Schaeffer – Interface … [...]

  2. THOMAS FRANK says:

    I’m trying to use your script for the input text prompt but it doesn’t seem to be working. I have javascipt enabled on google chrome browser but all I get is the title tool tips when I hover my mouse over the form field. I’m not getting the grey prompt text inside the field that should dissappear when you start typing.

    Is there anything else I need to add to the code besides the javascipt and style beginning and ending tags?

    sorry, I’m a bit of a newbie at this :)

  3. Hi, Thomas. You’ll also have to make sure you attach the jQuery script to your page. If you don’t have jQuery attached, my script won’t do anything. You can find out more information about jQuery and how to attach it to your page at http://www.jquery.com.

  4. Jim Duncan says:

    Hi Kyle,

    A very elegent solution to a common problem; well done.

    Question: could the script be modified in such a way as to allow right-click to hide the label as well? When right-clicking on the text in the span, the right-click event is captured by the span itself; instead of getting an input contect menu (with paste) I get the usual page context menu (view source, etc.).

    I’m using IE8, btw.

  5. Ben says:

    Awesome.

  6. Zach Zurn says:

    Thank you for this piece of code. It works well!

  7. Cedric says:

    Does this code work in IE7?

  8. Vadim says:

    Hi Kyle!
    All works fine. One problem is when a browser autocompletes the form the prompt text is overlapped by the autocomplete data. What should I do to resolve this?

    • Kyle says:

      Hi, Vadim. Thanks for bringing this up! I think I may need to check the value of the input on document ready to see if I need to remove the prompt text right off the bat. Look for an update coming to this post soon.

  9. Vadim says:

    Thank you, Kyle!
    May be I’m mistaken, ‘document ready’ is helpful but doesn’t cover all cases. On login forms a user can start to type e.g. his login, then browser will offer to select one, the user will choose it and after that the browser will autocomplete a password field (‘****’) and this will cause overlapping (if the password field previously had a prompt text).
    Anyway looking for the post update.
    Thank you!

  10. Hey, what a great tutorial!

    I can read everything but the jQuery…is there code available online to accomplish this on an email sign up form like here:

    http://www.taoofyouth.atsis.com/

  11. Kyle says:

    Hi, Dainis. If you put the jQuery in my post into a <script> tag or an attached JS file, it should run automatically on page load. Just make sure you have the jQuery script library attached to your page before my script can run.

  12. Steve E says:

    I had a problem with the SPAN becoming DISPLAY:BLOCK in the SHOW() method. I added the following to explicitly use inline.
    jQuery(promptSpan).attr(‘style’, ‘display:inline’);

    I was having the same issue on Firefox and Chrome. I have a Form with three by two matrix of fields. 2nd and 3rd columns were having display problems.

  13. Edwin Smalling says:

    Hello Kyle,

    This worked flawlessly for me across all browsers with the exception of Firefox which renders the text in the wrong location upon page load, this is corrected as soon as one clicks in the input box. Do you have any idea what causes this and perhaps how it might be remedied?
    Here is a link to the working page where it is implemented:

    http://www.thisisponyattack.com/2010/nav-structure.html

    Thank you in advance for any suggestions.

    • Kyle says:

      Hi, Edwin. I tested your site on Firefox both in Mac and Windows and it seemed to be working okay for me — maybe an older version or something?

      I will say that adding line-height: 1em; to the .input-prompt style rule will help you standardize the positioning/spacing across browsers and operating systems. Best of luck!

    • David G says:

      Same was happening to me, the fix is simple, just add display:block to .input-prompt and that will do the magic.

      (problem solved on Firefox 7.0.1)

  14. Natalie Wood says:

    Thanks heaps Kyle
    I wanted to only have some of my input fields with input prompt text.
    In case anyone else wants the same functionality – here is what I did:

    I modified the code so that for “text” input fields only those with a given ID would have the input prompt text added.

    Updated:
    $('input[type=text][title],input[type=password][title],textarea[title]').each(function(i){

    to

    $('input#formquery[type=text][title],input[type=password][title],textarea[title]').each(function(i){

    and the html from:

    to

  15. Natalie Wood says:

    oops – the html bit got lost

    and the html from:

    input type="text" title="Enter search keywords..."

    to

    input id="formquery" type="text" title="Enter search keywords..."

  16. hank m says:

    Really elegant- thanks for the tip.

  17. Lisa G says:

    Hi,

    I have used this very successfully on my site. However, there is just one problem on safari on Mac – on a search form I have, when the search button is clicked and the results are shown below, on safari, it replaces the prompt text OVER the search text that is still in the input field. On all other browsers I have tested it on, if the entered value remains in the input box, the prompt does not reappear. I hope that makes sense!

    For example, if you click on the input field, the prompt disappears and you enter your search term. You click ‘go’ and the results appear below while the search term is still shown inside the input box. In all browsers except safari on mac (no probs on safari for windows), the prompt text remains hidden. How do I keep it hidden on Safari too?

  18. Lisa G says:

    no help on this?

    • Kyle says:

      Lisa, it should check to see if the textbox has a pre-existing value. I haven’t seen the behavior you describe in Safari/Mac. In the code, I’m using if($(this).val() != ''){ $(promptSpan).hide(); } to hide the prompt if there is already something in the box. Are you doing something with JavaScript to fill in the value of the box after the page has loaded?

  19. Benson says:

    I’ve used this successfully in the past, but I notice that your demos aren’t working for me (Chrome, Win7)

  20. Peachy says:

    Kyle,

    I got the script working, and it’s great! However, for some reason in Chrome, once you click in the field the prompt text starts collecting at the top of the form. Any ideas on what could be going wrong?

  21. Kyle says:

    For all of you who might be having issues with this script, definitely keep an eye on the new placeholder feature of HTML5. There is a good cross-browser implementation of this script here: http://www.hagenburger.net/BLOG/HTML5-Input-Placeholder-Fix-With-jQuery.html

  22. Mauli says:

    Hi…this is to good script..

    Thanks..!!

  23. Joe says:

    I don’t suppose you know how to do this on an Access 2010 Web Form?

  24. Robert Frost says:

    Append a little span tag, one-two-three,
    What does the schmoe without javascript see?

  25. Florian Glashauser says:

    Hey dudes,
    i created a jQuery-Plugin out of it:
    http://code.google.com/p/jquery-input-prompt/

  26. AlbeyAmakiir says:

    Is there anything special for adding this to a drupal page? I see nothing, yet the javascript is added to the theme’s .info document.

  27. Valentin says:

    I liked you explanation about separation of label and input. I’m going to use your code on our site, with slight modifications:
    1) I use .css(‘display’, ‘inline’) instead of .show(), because even if initial inline CSS was ‘display: inline’, jQuery mistakingly sets it to ‘block’ when.
    2) as we know exactly where our prompt span is in relation to the input, it is not necessary to encode association between elements using class and id properties. I use .prev() and .next() methods for that.

    [code]
    $('input[type=text][title], input[type=password][title]').each(function(i) {

    var promptSpan = $('' + $(this).attr('title') + '');
    $(promptSpan).click(function() {
    $(this).hide().next().focus();
    });

    $(this).before(promptSpan).
    focus(function() {
    $(this).prev().hide();
    }).
    blur(function() {
    if($(this).val() === '')
    $(this).prev().css('display', 'inline');
    });
    });
    [/code]

  28. margaret says:

    Hi.. i had implemented a similar solution, and i have a problem that i just saw in you example too..

    I f I wrote a text in the input field and I reloaded the browser the text is still there. I tried many things.. but the text is not really in the input.. I dont Know why.. maybe you know what happen and have an idea about what can i do? I need the form empty each time the user enters.

    Tnks..

  29. Nikos says:

    For me this only works in IE :(

  30. sathavorn says:

    thank u

  31. Markyys says:

    I have adapted your code example into a jQuery plugin. Check it out if you’re interested.
    Unlike Florian’s, it follows the objectives laid out in the description of intended functionality.

    Thanks for this post; it was exactly what I needed.