Rectangle 27 27

It uses a combination of CSS3 and JavaScript to show the placeholder without adding to the content of the div:

<div contenteditable='true' data-placeholder='Enter some text'></div>
div[data-placeholder]:not(:focus):not([data-div-placeholder-content]):before {
    content: attr(data-placeholder);
    float: left;
    margin-left: 5px;
    color: gray;
}
(function ($) {
    $('div[data-placeholder]').on('keydown keypress input', function() {
        if (this.textContent) {
            this.dataset.divPlaceholderContent = 'true';
        }
        else {
            delete(this.dataset.divPlaceholderContent);
        }
    });
})(jQuery);

NB: Since I wrote this answer, I've updated the plugin for IE compatibility and non-div elements. See the linked GitHub repo for the latest version.

Does it work if I am setting div text from backend? In my case placeholder and my text are concated

javascript - Placeholder in contenteditable - focus event issue - Stac...

javascript jquery focus contenteditable caret
Rectangle 27 23

You may need to manually update the selection. In IE, the focus event is too late, so I would suggest using the activate event instead. Here's some code that does the job in all major browsers, including IE <= 8 (which a CSS-only alternative will not):

$('div').on('activate', function() {
    $(this).empty();
    var range, sel;
    if ( (sel = document.selection) && document.body.createTextRange) {
        range = document.body.createTextRange();
        range.moveToElementText(this);
        range.select();
    }
});

$('div').focus(function() {
    if (this.hasChildNodes() && document.createRange && window.getSelection) {
        $(this).empty();
        var range = document.createRange();
        range.selectNodeContents(this);
        var sel = window.getSelection();
        sel.removeAllRanges();
        sel.addRange(range);
    }
});

Another +1 for the RangeMaster. I thought by keeping it simple I'd be avoiding the cross browser issues, but that was rather naive of me.

Ive been banging my head the last two days on this one, trying all kinds of quirks. I was even adding an absolute positioned placeholder at the back of my head, so this solution is simple enough for me! I agree though, there should be a simpler solution...

Awesome! You saved me a lot of headaches :)

javascript - Placeholder in contenteditable - focus event issue - Stac...

javascript jquery focus contenteditable caret
Rectangle 27 20

span.spanclass:empty:before {content:"placeholder";}

This works like a charm.

Works just like the native placeholder behavior, perfect!

javascript - Placeholder in contenteditable - focus event issue - Stac...

javascript jquery focus contenteditable caret
Rectangle 27 8

I found that the best way to do this is to use the placeholder attribute like usual and add a few lines of CSS.

<div contenteditable placeholder="I am a placeholder"></div>
[contenteditable][placeholder]:empty:before {
    content: attr(placeholder);
    color: #bababa;
}

Note: the CSS :empty selector only works if there is literally nothing in-between the opening and closing tag. This includes new lines, tabs, empty space, etc.

This solution has an issue in FF. on near right side border if you click twice, cursor hangs there.

javascript - Placeholder in contenteditable - focus event issue - Stac...

javascript jquery focus contenteditable caret
Rectangle 27 149

Here is a CSS only solution augmenting some of the other answers:-

<div contentEditable=true data-ph="My Placeholder String"></div>
<style>
    [contentEditable=true]:empty:not(:focus)::before{
        content:attr(data-ph)
    }
</style>

EDIT2: Be advised, this method doesn't work 100% for multi-line applications due to residual <br> elements being present in the div after performing a select-all-cut or select-all-delete on all lines. Credits:- @vsync Backspace seems to work fine (at least on webkit/blink)

This would be exceptionally cool, except... can't get it to work. Can you post a working jsfiddle?

This should be the accepted answer. It's a little more complicated than the one from @amwinter but it keeps the placeholder in the html instead of the css.

True! Another advantage of the complexity tradeoff is that if you have multiple contentEditable elements, all you have to do is specify a data-ph placeholder for each and the same CSS code takes care of all of them.

This is NOT the answer, this fails and is unreliable. Try writing 2 lines text, then select all and delete. there will still be some junk HTML inside the contentEditable, which will prevent the :empty from being triggered. fail.

You're right @vsync! That's a very good find. Thank you for sharing.

javascript - Placeholder in contenteditable - focus event issue - Stac...

javascript jquery focus contenteditable caret
Rectangle 27 6

All you need is this little solution

[contenteditable=true]:empty:before{
  content: attr(placeholder);
  display: block; /* For Firefox */
}

Works. Tested in firefox, chrome, and Safari.

javascript - Placeholder in contenteditable - focus event issue - Stac...

javascript jquery focus contenteditable caret
Rectangle 27 4

Works exactly like the html5 placeholder attribute!

  • Hides itself right away when you input the first letter
  • Shows itself again when you delete what you input into it
<div class="placeholder" contenteditable="true"></div>
.placeholder:after {
    content: "Your placeholder"; /* this is where you assign the place holder */
    position: absolute;
    top: 10px;
    color: #a9a9a9;
}
$('.placeholder').on('input', function(){
    if ($(this).text().length > 0) {
        $(this).removeClass('placeholder');
    } else {
        $(this).addClass('placeholder');
    }
});
input

javascript - Placeholder in contenteditable - focus event issue - Stac...

javascript jquery focus contenteditable caret
Rectangle 27 1

Here's the fix that I used.

<div contenteditable><em>Edit me</em></div>
<script>
$('div').focus(function() {
    var target = $(this);
    window.setTimeout(function() { target.empty(); }, 10);
});
</script>

javascript - Placeholder in contenteditable - focus event issue - Stac...

javascript jquery focus contenteditable caret
Rectangle 27 0

span.spanclass:empty:before {content:"placeholder";}

This works like a charm.

javascript - Placeholder in contenteditable - focus event issue - Stac...

javascript jquery focus contenteditable caret
Rectangle 27 0

It uses a combination of CSS3 and JavaScript to show the placeholder without adding to the content of the div:

<div contenteditable='true' data-placeholder='Enter some text'></div>
div[data-placeholder]:not(:focus):not([data-div-placeholder-content]):before {
    content: attr(data-placeholder);
    float: left;
    margin-left: 5px;
    color: gray;
}
(function ($) {
    $('div[data-placeholder]').on('keydown keypress input', function() {
        if (this.textContent) {
            this.dataset.divPlaceholderContent = 'true';
        }
        else {
            delete(this.dataset.divPlaceholderContent);
        }
    });
})(jQuery);

NB: Since I wrote this answer, I've updated the plugin for IE compatibility and non-div elements. See the linked GitHub repo for the latest version.

javascript - Placeholder in contenteditable - focus event issue - Stac...

javascript jquery focus contenteditable caret
Rectangle 27 0

I found that the best way to do this is to use the placeholder attribute like usual and add a few lines of CSS.

<div contenteditable placeholder="I am a placeholder"></div>
[contenteditable][placeholder]:empty:before {
    content: attr(placeholder);
    color: #bababa;
}

Note: the CSS :empty selector only works if there is literally nothing in-between the opening and closing tag. This includes new lines, tabs, empty space, etc.

javascript - Placeholder in contenteditable - focus event issue - Stac...

javascript jquery focus contenteditable caret
Rectangle 27 0

Here's the fix that I used.

<div contenteditable><em>Edit me</em></div>
<script>
$('div').focus(function() {
    var target = $(this);
    window.setTimeout(function() { target.empty(); }, 10);
});
</script>

javascript - Placeholder in contenteditable - focus event issue - Stac...

javascript jquery focus contenteditable caret
Rectangle 27 0

Works exactly like the html5 placeholder attribute!

  • Hides itself right away when you input the first letter
  • Shows itself again when you delete what you input into it
<div class="placeholder" contenteditable="true"></div>
.placeholder:after {
    content: "Your placeholder"; /* this is where you assign the place holder */
    position: absolute;
    top: 10px;
    color: #a9a9a9;
}
$('.placeholder').on('input', function(){
    if ($(this).text().length > 0) {
        $(this).removeClass('placeholder');
    } else {
        $(this).addClass('placeholder');
    }
});
input

javascript - Placeholder in contenteditable - focus event issue - Stac...

javascript jquery focus contenteditable caret
Rectangle 27 0

Here is a CSS only solution augmenting some of the other answers:-

<div contentEditable=true data-ph="My Placeholder String"></div>
<style>
    [contentEditable=true]:empty:not(:focus):before{
        content:attr(data-ph)
    }
</style>

EDIT2: Be advised, this method doesn't work 100% for multi-line applications due to residual <br> elements being present in the div after performing a select-all-cut or select-all-delete on all lines. Credits:- @vsync Backspace seems to work fine (at least on webkit/blink)

This would be exceptionally cool, except... can't get it to work. Can you post a working jsfiddle?

@ccleve Check the my edit. Hope you dont mind my using codepen. Jsfiddle acted up on me severaly (and i find codepen having better features)

This should be the accepted answer. It's a little more complicated than the one from @amwinter but it keeps the placeholder in the html instead of the css.

True! Another advantage of the complexity tradeoff is that if you have multiple contentEditable elements, all you have to do is specify a data-ph placeholder for each and the same CSS code takes care of all of them.

You're right @vsync! That's a very good find. Thank you for sharing.

javascript - Placeholder in contenteditable - focus event issue - Stac...

javascript jquery focus contenteditable caret
Rectangle 27 0

var curText = 'Edit me';
$('div').focusin(function() {
    if ($(this).text().toLowerCase() == curText.toLowerCase() || !$(this).text().length) {
        $(this).empty();
    }
}).focusout(function() {
    if ($(this).text().toLowerCase() == curText.toLowerCase() || !$(this).text().length) {
        $(this).html('<em>' + curText + '</em>');
    }
});

Thanks, but the problem is not that I dont know how to save the placeholder text, but the fact that the caret disappears when clearing the placeholder text.

javascript - Placeholder in contenteditable - focus event issue - Stac...

javascript jquery focus contenteditable caret
Rectangle 27 0

var curText = 'Edit me';
$('div').focusin(function() {
    if ($(this).text().toLowerCase() == curText.toLowerCase() || !$(this).text().length) {
        $(this).empty();
    }
}).focusout(function() {
    if ($(this).text().toLowerCase() == curText.toLowerCase() || !$(this).text().length) {
        $(this).html('<em>' + curText + '</em>');
    }
});

Thanks, but the problem is not that I dont know how to save the placeholder text, but the fact that the caret disappears when clearing the placeholder text.

javascript - Placeholder in contenteditable - focus event issue - Stac...

javascript jquery focus contenteditable caret
Rectangle 27 0

You may need to manually update the selection. In IE, the focus event is too late, so I would suggest using the activate event instead. Here's some code that does the job in all major browsers, including IE <= 8 (which a CSS-only alternative will not):

$('div').on('activate', function() {
    $(this).empty();
    var range, sel;
    if ( (sel = document.selection) && document.body.createTextRange) {
        range = document.body.createTextRange();
        range.moveToElementText(this);
        range.select();
    }
});

$('div').focus(function() {
    if (this.hasChildNodes() && document.createRange && window.getSelection) {
        $(this).empty();
        var range = document.createRange();
        range.selectNodeContents(this);
        var sel = window.getSelection();
        sel.removeAllRanges();
        sel.addRange(range);
    }
});

Another +1 for the RangeMaster. I thought by keeping it simple I'd be avoiding the cross browser issues, but that was rather naive of me.

Ive been banging my head the last two days on this one, trying all kinds of quirks. I was even adding an absolute positioned placeholder at the back of my head, so this solution is simple enough for me! I agree though, there should be a simpler solution...

Awesome! You saved me a lot of headaches :)

javascript - Placeholder in contenteditable - focus event issue - Stac...

javascript jquery focus contenteditable caret