What is the most accurate way to emulate the "placeholder" attribute in browsers that don't support it natively?

Solution 1:

"Most code I've seen takes the value of the placeholder and stuffs it into the input itself which leads to this problem"

Well, that's pretty much what the placeholder text does behind the scenes (albeit, it's not literally updating the value of the input).

One option is to something akin to this:

http://fuelyourcoding.com/scripts/infield/

The concept there is you move the LABEL with CSS so that's on top of the field and looks like placeholder text. Note that a LABEL isn't necessarily the same as placeholder text. A LABEL is important to have, especially for accessibility, while placeholder text can be thought more as 'help text' in addition to the label.

The other option is what you've been doing, take the content of the placeholder attribute and move it into the value of the input itself via JS.

Where you're getting hung up is you are submitting the form before checking to see if the fake placeholder text is still there.

To get around that, you want to attach an event to the submission of the form that, before submitting the form, will first look at all the input fields, grab their values, compare it to their placeholder attributes, and if it matches, set the value to blank.

UPDATE:

To address the issue you brought up in a comment of the user-inputted value matching the placeholder text, you could do something like this:

$('input[placeholder]').each(function(){

 if($(this).val() === $(this).attr('placeholder')){
      // in the odd situation where the field is prepopulated with
      // a value and the value just happens to match the placeholder,
      // then we need to flag it
      $(this).data('skipCompare','true');
  }    

// move the placeholder text into the field for the rest of the blank inputs
   if($(this).val().length===0){
       $(this).val($(this).attr('placeholder'))
   }

// move the placeholder text into the field for the rest of the blank inputs
  if($(this).val().length===0){
      $(this).val() = $(this).attr('placeholder');
  }


  $(this)
     .focus(function(){
           // remove placeholder text on focus
           if($(this).val()==$(this).attr('placeholder')){
               $(this).val('')
           }
     })
     .blur(function(){
         // flag fields that the user edits
         if( $(this).val().length>0 && $(this).val()==$(this).attr('placeholder')){
             $(this).data('skipCompare','true');
         }
         if ( $(this).val().length==0){
             // put the placeholder text back
             $(this).val($(this).attr('placeholder'));
         }
     })


 })

 $('#submitButton').click(function(){
   $('input[placeholder]').each(function(){
     if( !($(this).data('skipCompare')) && $(this).val() == $(this).attr('placeholder')     ){
         $(this).val('');
     };
     alert($(this).val());
   })
})

It's late and I'm tired so all that might be completely wrong. No warranties given. ;)

Solution 2:

jquery plugin I wrote a while ago:

(function(){
    $.fn.inactiveText = function(inactiveClass, defaultValue){
        var a, b;
        this
            .data    ('defaultValue', defaultValue)
            .addClass('inactive')
            .focus(a=function(){
                var $this = $(this);
                if($this.hasClass(inactiveClass)){
                    (valFn.apply($this) == defaultValue) && $this.val('');
                    (valFn.apply($this) != defaultValue) && $this.removeClass(inactiveClass);
                }
    //            $this.hasClass(inactiveClass) && $this.valueIs(defaultValue).val('').end().valueIsNot(defaultValue).removeClass(inactiveClass);
            })
            .blur(b=function(){
                var $this = $(this);
                this.value || $this.addClass(inactiveClass).val(defaultValue);
            });
        this.each(a);
        this.each(b);

        this.setDefaultValue = function(d){
            this.each(a);
            defaultValue = d;
            this.each(b);
        };

        return this;
    };

    var valFn = $.fn.val;

    $.fn.val = function(v){
        if(typeof(v) == 'undefined'){
            var val = valFn.apply(this, arguments);
            return val == this.data('defaultValue') ? '' : val;
        }

        return valFn.apply(this, arguments);
    };
})();

Define a css class for the inactive style (e.g. grey text) and you're good to go.

updated fiddle: http://jsfiddle.net/cwolves/At8cu/1/