27

Is there a freely available jQuery plugin that changes placeholder behavior to match HTML5 spec?

Before Focus
chrome unfocused placeholder

On Focus Good (Safari)
safari focused placeholder

On Focus Bad (Chrome, Firefox)
chrome focused placeholder

You can what your browser does with this simple fiddle.

HTML5 draft spec says:

User agents should present this hint to the user, after having stripped line breaks from it, when the element's value is the empty string and/or the control is not focused (e.g. by displaying it inside a blank unfocused control and hiding it otherwise).

The "/or" is new in current draft so I suppose that's why Chrome and Firefox don't support it yet. See WebKit bug #73629, Chromium bug #103025.

Dan Abramov
  • 264,556
  • 84
  • 409
  • 511
  • 1
    Your fiddle works for me (placeholder doesn't disappear on focus) on Chrome 17.0.963.12. – ThinkingStiff Dec 26 '11 at 02:19
  • @ThinkingStiff, Chrome says 16.0.921 is the last version available for me (might be because of localization or different channel). Anyway, I'm looking for a JS fix that will work for older versions. – Dan Abramov Dec 26 '11 at 02:26
  • @ThinkingStiff where did you find Chrome 17? Do they provide nightlies? – canon Dec 30 '11 at 15:09
  • 1
    @antisanity I'm on the dev channel: http://dev.chromium.org/getting-involved/dev-channel – ThinkingStiff Dec 30 '11 at 20:01
  • By the way, there's also a related [Firefox bug #673873](https://bugzilla.mozilla.org/show_bug.cgi?id=673873). – naktinis Mar 21 '12 at 16:57
  • 1
    I have recently updated my [Placeholders.js](https://github.com/jamesallardice/Placeholders.js) polyfill to support this. Works in pretty much all browsers, including IE6, and has no dependency on jQuery. – James Allardice Jul 26 '12 at 10:48
  • 2
    Surely "e.g. by displaying it inside a blank unfocused control and hiding it otherwise" means that this behaviour is allowed by the spec. I'd also suggest that having the placeholder text hidden on focus is far more usable for most people (I've watched several people try to select the placeholder text to delete it before typing). – pelms Nov 28 '13 at 15:56
  • 1
    Why not trust that the browser is doing the right job? The browser knows what's best way better than the developer (each browser can be configured to the user's likings). – brunoais May 02 '14 at 10:39

6 Answers6

15

Stefano labels

Stefano J. Attardi wrote a nice jQuery plugin that just does that.
It is more stable than Robert's and also fades to a lighter grey when the field gets focused.


I modified his plugin to read placeholder attribute as opposed to manually creating a span.
This fiddle has complete code:

HTML

<input type="text" placeholder="Hello, world!">

JS

// Original code by Stefano J. Attardi, MIT license

(function($) {
    function toggleLabel() {
        var input = $(this);

        if (!input.parent().hasClass('placeholder')) {
            var label = $('<label>').addClass('placeholder');
            input.wrap(label);

            var span = $('<span>');
            span.text(input.attr('placeholder'))
            input.removeAttr('placeholder');
            span.insertBefore(input);
        }

        setTimeout(function() {
            var def = input.attr('title');
            if (!input.val() || (input.val() == def)) {
                input.prev('span').css('visibility', '');
                if (def) {
                    var dummy = $('<label></label>').text(def).css('visibility','hidden').appendTo('body');
                    input.prev('span').css('margin-left', dummy.width() + 3 + 'px');
                    dummy.remove();
                }
            } else {
                input.prev('span').css('visibility', 'hidden');
            }
        }, 0);
    };

    function resetField() {
        var def = $(this).attr('title');
        if (!$(this).val() || ($(this).val() == def)) {
            $(this).val(def);
            $(this).prev('span').css('visibility', '');
        }
    };

    var fields = $('input, textarea');

    fields.live('mouseup', toggleLabel); // needed for IE reset icon [X]
    fields.live('keydown', toggleLabel);
    fields.live('paste', toggleLabel);
    fields.live('focusin', function() {
        $(this).prev('span').css('color', '#ccc');
    });
    fields.live('focusout', function() {
        $(this).prev('span').css('color', '#999');
    });

    $(function() {
       $('input[placeholder], textarea[placeholder]').each(
           function() { toggleLabel.call(this); }
       );
    });

})(jQuery);

CSS

.placeholder {
  background: white;
  float: left;
  clear: both;
}
.placeholder span {
  position: absolute;
  padding: 5px;
  margin-left: 3px;
  color: #999;
}
.placeholder input, .placeholder textarea {
  position: relative;
  margin: 0;
  border-width: 1px;
  padding: 6px;
  background: transparent;
  font: inherit;
}

/* Hack to remove Safari's extra padding. Remove if you don't care about pixel-perfection. */
@media screen and (-webkit-min-device-pixel-ratio:0) {
    .placeholder input, .placeholder textarea { padding: 4px; }
}
Alireza
  • 100,211
  • 27
  • 269
  • 172
Dan Abramov
  • 264,556
  • 84
  • 409
  • 511
  • Seems decent, but the github repo wasn't updated in two years ... I'm reluctant to use stale code. – ripper234 May 06 '12 at 10:56
  • 4
    @ripper: Could this possibly mean that the code just works? I suggest you try to use it, and if you find any problems, feel free to fork it and fix them. But if you find a better solution, please let us know. – Dan Abramov May 06 '12 at 11:01
  • It could mean that ... it's just not very confidence-inspiring ... but I guess I'll give it a spin. – ripper234 May 06 '12 at 12:41
  • @ripper: It worked for me fairly well, except for some font size issues I can't recall exactly. – Dan Abramov May 06 '12 at 13:00
  • A caveat: This requires a lot of CSS, and some of it interferes with my own. Some other plugins I've seen don't require any CSS to function (although I admit I found none that solves the focus problem). – ripper234 May 06 '12 at 13:03
  • 1
    you also need fields.live('mouseup', toggleLabel); to show the placeholder when user clicks on the reset ([X]) icon in IE – xorcus Jan 27 '14 at 16:02
  • "live" is deprecated. For current versions of JQuery, replace all instances of "live" with "on" – Whatever Man Jul 01 '15 at 19:05
4

Robert Nyman discusses the problem and documents his approach in his blog.
This fiddle that has all the neccessary HTML, CSS and JS.

enter image description here

Unfortunately, he solves the problem by changing value.
This will not work by definition if placeholder text is itself a valid input.

Dan Abramov
  • 264,556
  • 84
  • 409
  • 511
3

I found this question by googling out the solution to the same problem. It seems that existing plugins either don't work in elder browsers or hide placeholder on focus.

So I decided to roll on my own solution while trying to combine best parts from existing plugins.

You may check it out here and open an issue if you face any problems.

RevanthKrishnaKumar V.
  • 1,855
  • 1
  • 21
  • 34
Andrey Kuzmin
  • 4,479
  • 2
  • 23
  • 28
  • Andrew this is awesome! Works like a charm. Thanks for saving me time & having to do it myself :) – RamRovi Jul 15 '15 at 19:30
2

How about something simple like this? On focus save out the placeholder attribute value and remove the attribute entirely; on blur, put the attribute back:

$('input[type="text"]').focus( function(){
  $(this).attr("data-placeholder",$(this).attr('placeholder')).removeAttr("placeholder");
});
$('input[type="text"]').blur( function(){
  $(this).attr("placeholder",$(this).attr('data-placeholder'));
});   
Logan
  • 21
  • 2
1

I wrote my own css3 only solution. See if that fullfills all your needs.

http://codepen.io/fabiandarga/pen/MayNWm

This is my solution:

  1. the input element is set to "required"
  2. an aditional span element for the placeholder is needed. This element is moved on top of the input element (position: absolute;)
  3. with css selectors the input element is tested for validity (required fields are invalid as long as there is no input) and the placeholder is then hidden.

Pitfall: The placeholder is blocking mouseevents to the input! This problem is circumvented by hiding the placeholder element when the mouse is inside the parent (wrapper).

<div class="wrapper">
  <input txpe="text" autofocus="autofocus" required/>
  <span class="placeholder">Hier text</span>
</div>

.placeholder {
  display: none;
  position: absolute;
  left: 0px;
  right: 0;
  top: 0px;
  color: #A1A1A1;
}
input:invalid + .placeholder {
  display: block;  /* show the placeholder as long as the "required" field is empty */
}
.wrapper:hover .placeholder {
  display: none; /* required to guarantee the input is clickable */
}

.wrapper{
  position: relative;
  display: inline-block;
}
Fabian
  • 480
  • 6
  • 11
0

Maybe you can try with Float Label Pattern :)

See Float labels in CSS

RevanthKrishnaKumar V.
  • 1,855
  • 1
  • 21
  • 34
herchila
  • 1
  • 1