Check out my latest project: Code Dumper

jQuery tutorial: Text box hints

Updated March '08: I've separated the plugin to a separate jquery.hint.js file and included a fix to get around Firefox's autocomplete

You will see a lot of web sites with search boxes have text already populated inside of the field and when you select the input text box it disappears and reappears when it’s not selected.

This tutorial will show you how can add a small amount of jQuery to add this feature to any of your web sites.

The Goal

  1. To create a jQuery plugin.
  2. Show a ‘hint’ inside the input box when it is not in focus†† (aka blurred).
  3. Hide the hint when the text input has focus.

† The hint is what I am calling the text that appears and disappears within the input box.

†† Focus is the term (in this case) to indicate the user’s cursor is in the text field. Blurred is the opposite.

Demo

Our demo shows a input box for a finance web site that allows the user to search by company name or by the symbol (ticker).

See the demo in action

How it will work

  1. We are going to get the hint from the ‘title’ attribute of the input box.
  2. When the input box has focus we will hide the hint - only if the text in the input box matches the title attribute.
  3. When the input box is blurred, and it doesn’t contain any text, we will show the text again.
  4. If the input box is blurred and does contain text, we won’t do anything.

Unobtrusive JavaScript

The first step is to design the HTML so that it will work sensibly without JavaScript turned on, i.e. we’re not going to put our hint in the input box. Since we are planning to put the hint in the title tag we’re set to code.

The Code

HTML


<form action="">
    <div><label for="search">Search:</label>
    <input type="text" name="seach" value="" id="search" title="Company name or ticker" />
    <input type="submit" value="Go" />
    </div>
</form>

Pretty simple - nothing unexpected there.

jQuery Plugin


jQuery.fn.hint = function () {
  return this.each(function (){
    // get jQuery version of 'this'
    var t = jQuery(this); 
    // get it once since it won't change
    var title = t.attr('title'); 
    // only apply logic if the element has the attribute
    if (title) { 
      // on blur, set value to title attr if text is blank
      t.blur(function (){
        if (t.val() == '') {
          t.val(title);
          t.addClass('blur');
        }
      });
      // on focus, set value to blank if current value 
      // matches title attr
      t.focus(function (){
        if (t.val() == title) {
          t.val('');
          t.removeClass('blur');
        }
      });

      // clear the pre-defined text when form is submitted
      t.parents('form:first()').submit(function(){
          if (t.val() == title) {
              t.val('');
              t.removeClass('blur');
          }
      });

      // now change all inputs to title
      t.blur();
    }
  });
}

Here’s a breakdown of some of what’s going on:

return this.each(function() {

Ensure we are applying the plugin to all the matched elements and allowing our plugin to be chained.

var t = jQuery(this)

Creating a cached copy of the jQuery object so we can use jQuery’s functions for testing, without the overhead of continuously making new jQuery objects.

t.blur(function(){

When the element loses focus - execute the function that has been passed in. In our case, we are testing whether the field has been left blank, and if it has - we set it to the title attribute (cached earlier).

We are also adding a class called ‘blur’ to the input box so as to give the user the impression that the text that appears in the box has not been entered by them. Note that we remove this class when the element takes focus.

t.blur()

We end up with a final call to the blur method - so that all the matched elements are set by default as blurred (i.e. with the title attribute appearing in the text already).

If you’re curious, you can read more about writing jQuery plugins.

Where to take it next

Within the plugin, you could add better validation to ensure we are only applying to input elements where type is ‘text’.

Update June '07: You can view and use the label over plugin for an accessible version of the 'text hints'

There are a couple of places you could look at to improve the plugin. The first that I can think of is to apply the label element to float inside the element (as seen on Digg’s search and explained over at A List Apart: Making Compact Forms More Accessible).

The second upgrade you could make would whether you can use this kind of plugin for a select input type. I haven’t thought it through, but it could be interesting.

Let me know if you have any comments or need to point out any errors.

37 Responses to “jQuery tutorial: Text box hints”

  1. Doh! I forgot to include how to apply the plugin:

    $('input:text').hint();

  2. Hey dude where's your hints on the leave a reply form ;) Seriously thanks alot, planning to give your code a try.
    Thanks for the link to the ALA article also.

  3. LOL! Good point. Do as I say, not as I do ;-)

  4. Great, exactly what i needed.
    Would be nice to see how to pass arguments to functions, expecially a settings-array, and how to apply it to the function.
    But this is a great start for me.

  5. [...] The labelOver plugin is a follow on from the text hints, but in fact the best practise solution. [...]

  6. I just stumbled upon this page while looking for exactly this function. However, I know nothing about jQuery.

    Where do the various pieces go in relation to the form input? So far i'm seeing the raw text of the jQuery come up.

    Thanks

  7. thank you, I have been looking for something like this for a looong time.

    Pz

  8. Minor problem - is there supposed to be a last closing bracket in the end? I didn't work for me until I removed it. Makes sense to me, as it doesn't seem to close anything.

  9. Oh, one more thing. You should add "t.addClass('blur');" after "t.blur()", which causes them all to obtain the .blur class upon initiation. Use that class in your CSS to style the text while in its "hint mode". That way you can get, for example, gray text for hints but regular black text while something else is being typed.

  10. @Steax - thanks for the catch - I've removed the bracket now.

    On your second point - you don't need to, and shouldn't add the t.addClass('blur') after for these reasons:

    1) On calling t.blur() - we've set a custom handler to add the blur class if there's no text.
    2) If we did add the blur as a last thing, it might blur the text if there is already content in it (i.e. Firefox keeps textboxes populated if the page is refreshed, or if it were dynamically populated).

    Thanks again.

  11. Oh, alright, gotcha. Thanks for the script. =)

  12. A minor enhancement - removes any values that match the title when the form is submitted.

    t.parents('form:first()').submit(function(){
      if (t.val() == title) {
        t.val('');
        t.removeClass('blur');
      }
    })
  13. GreyCells, where are you supposed to add that function?

  14. @Josh - I've added GreyCell's suggestion in to the tutorial code so you can see where it belongs.

  15. Thanks heaps! just what I was looking for. However is there a way of applying this to a Password input field as well so that it initially appears as asterisks/dots?

  16. Thanks for the hint!!! It was really helpful. I'm beginning to study jQuery )

  17. If the input is same to the title, what will happen?

  18. @earsea - nothing! Give it a try and see.

  19. works great! I am curious if this could be editted some how to work on a textarea box?

  20. @Sam - unless I'm missing something, this does work on textareas. I've used it in the past, and it works exactly the same way it would on an input field...give it a try.

  21. Couldn't this be just as easily done without a plugin?

    // #search is the id of the textbox in this example
    // This still uses the value of the title attribute
    $('#search').focus(function() {
      // See if the input field is the default
      if ($(this).val() == $(this).attr('title')) {
        $(this).val('');
      }
    })
    .blur(function() {
      if ($(this).val() == '') {
        $(this).val($(this).attr('title'));
      }
    });

  22. @Everah, absolutely (except your example doesn't cover all the possibilities, but I understand the essence of your point).

    If you've got one web site/solution that uses the functionality in one place, then there's no point in using a plugin.

    However, I personally use the 'hint' plugin throughout a lot of my own work, so it's easy for me to include it in my plugins library and when I need it, in my main.js, I can just add:

    $('#search, #username, input.hint').hint(); // etc

    It just saves having to tweak the code each time I use it (i.e. in your code you'd need to change the selector it runs from).

  23. Thanks! This is just what I was looking for.

  24. Thanks Remy - just what I was looking for. Minor issue - when using firefox v2, both in my own usage and your demo example, I noticed that if you refresh the browser, the hint still appears but loses it's grey color. When you have a lot of input boxes on a page, this looks slightly strange, as the hints stand out too much. It this a bug or just a browser peculiarity? Weirdly the labelOver plugin does not share the same issue.

  25. @Al - thanks for pointing that out.

    It's the autocomplete feature working on Firefox that's sticking the value in. I've updated the demo so that the input has the autocomplete="off" attribute which will kill the issue.

    The reason the labelOver plugin doesn't have the same effect, is because the hint plugin actually puts a value in the input field, whereas labelOver places the label directly over the input field (so Firefox doesn't remember it as a value).

    I hope that helps.

  26. @Remy - thanks very much - that does indeed sort it and helps my problem solving massively.

    Unfortunately due to the auto-complete attribute not being valid XHTML, plus other issues specific to my use of it (using a javascript date picker alongside, which inherits the grey text class unfortunately), I am going to try your suggestion of using the labelOver plugin, which has the benefit of being accessible too.

    But for those not fussed over XHTML compliance, this does indeed sort things!

  27. @Al - I've written a nice simple fix to get around the autocomplete problem, and the XHTML remains valid. You can download the plugin from here: hint.jquery.js

  28. i don't know why but i'm getting an error ..
    $ is not defined
    $(function(){

  29. @Steve - either you're not importing jQuery, or you're importing the plugin before you're importing jQuery. Put the jQuery library as the first thing you do in the JavaScript and all should be well.

  30. [...] Text box hints- You will see a lot of web sites with search boxes have text already populated inside of the field and when you select the input text box it disappears and reappears when it’s not selected. This tutorial will show you how can add a small amount of jQuery to add this feature to any of your web sites. [...]

  31. Is there any reason that hinting doesn't support a dynamic title change? I.e. if the title attribute is changed via JS, hint() will continue hinting the previous title tag...

    Cheers.

  32. Going on... I thought the issue might be that when you change the title attribute the contents of the field no longer match and therefore it doesn't see it as a hint - that you would just need to remove the existing value prior to changing the title... However that doesn't seem to be the case.

    At this stage, this seems to have solved my issue though it would be good to know if there was an easier way...:

    Unbind blur + focus events

    $.fn.unhint = function(){
      return this.each(function () {
        var $$ = $(this);
        $$.unbind('focus').unbind('blur');
      });
    }

    On change of field execute a function called page, change title attribute, unbind, rebind and clear val()...

    
    $('#paging .custom').change(function(){
      page($(this).val());
      $(this).attr("title","Page "+pageNumber+" of n").unhint().hint().val("");
    });
    
  33. hi, is there any way to change the input title from "by name or ticker" to something else? very nice script by the way, it got me started on learning jquery. well, thanks.

  34. ok, please disregard, dumb question, i know... i guess my browser had some refresh issues, because when i closed the window and opened it again, the obvious solution worked just fine. sorry, my bad. again, nice script.

  35. One problem I see is when the user enter a text that is the same as the hint, it will get removed again. The following patch should fix this (by using the blur class as a hint, whether the input's value is a hint or user entered text:

    
    @@ -29,14 +29,14 @@
    
                 // on focus, set value to blank if current value matches title attr
                 .focus(function () {
    -                if ($$.val() == title) {
    +                if ($$.hasClass(blurClass)) {
                         $$.val('').removeClass(blurClass);
                     }
                 })
    
                 // clear the pre-defined text when form is submitted
                 .parents('form:first').submit(function () {
    -                if ($$.val() == title) {
    +                if ($$.hasClass(blurClass)) {
                         $$.val('').removeClass(blurClass);
                     }
                 }).end()
    
  36. @wd - funny, I was thinking about exactly that problem about 30 minutes ago. I'll that change in shortly.

    Thanks!

  37. WISH LIST ITEM:

    How difficult would it be to allow this to accept a LIST of words, and use jQuery effects to transition from word to word on a specified interval??

    I might want 6 words to get people some examples of things to search for, or our popular searches from the database. I would want them to fade in fade out and cycle through the words in the list.

    make sense?

    Awesome plugin so far, BTW.

Leave a Reply
Not required

CODE: Please escape code and wrap in <pre><code>, doing so will automatically syntax highlight