7

I've got a contenteditable div that, when empty (only the placeholder text is present per the CSS below), the user is able to click the right-hand side of the div and place the cursor there (see screenshot). Once the cursor is there, the user is unable to type at all. The issue only happens in Firefox (I'm in 33.1.1). The issue does not happen in any other browser.

HTML:

<div class="content-editable form-textarea font-face-frank"
    placeholder="Type something here..." contenteditable="true"
    ng-model="form.message" ng-class="form.fontName" strip-br="true" required></div>

CSS:

.content-editable {
    outline-width: 0;
    min-height: 1em;
    max-height: 300px;
    line-height: 1em;
    overflow-y: scroll;
    display: inline-block;
    width: 100%;
    font-size: 44px;
    padding: 10px;
}
.content-editable:empty:before {
    content: attr(placeholder);
}

What I've Tried:

  • Placing a space, <br> in the div - fixes issue, but then the placeholder text is not displayed;
  • Adding a &nbsp;, <br> via .content-editable:empty {}; the placholder text remains, but the cursor issue is not addressed.

Repro of the Issue

Screencap of cursor position

Update

Removing the content: attr(placeholder); css directive resolves the issue, not that doing that allows me to display the 'placeholder' text in the contenteditable element.

Unpossible
  • 10,607
  • 22
  • 75
  • 113
  • 1
    First off, nice question! Although `placeholder` seems to make sense on elements like `textarea`and `contenteditable` (see http://lists.w3.org/Archives/Public/public-whatwg/2012May/0001.html ), it currently is just meant to be used on `input` https://html.spec.whatwg.org/multipage/forms.html#the-placeholder-attribute. Can't reproduce it on my Fx 33.1.1. – Volker E. Nov 26 '14 at 16:54
  • @VolkerE. - really, the jsfiddle works? Hmm. Will add a screencap of what I am seeing in terms of cursor placement. – Unpossible Nov 26 '14 at 21:48
  • No issue with Firefox 31.2.0 ... and what is precisely your question? Maybe you just better fill a bug report. – Ortomala Lokni Dec 01 '14 at 16:00
  • @OrtomalaLokni question is laid out in detail - I and others are seeing the above issue with a contenteditable, as supplied in the jsfiddle. Glad that you aren't seeing it - can you let me know what OS you are on? – Unpossible Dec 01 '14 at 16:11
  • 33.1 has the problem, at first it went well but clicking all the way on the right causes the problem (Windows 8) – Timtech Dec 01 '14 at 21:55
  • Happening in 34.0, but only if clicked all the way at the right. User can still move it back over to the left and type. – Timtech Dec 01 '14 at 21:56
  • Nevermind, same issue both versions. Works fine in IE – Timtech Dec 01 '14 at 22:10
  • if anyone is having trouble reproducing the problem, please click at a place very close to the right blue-border, in firefox. – zhirzh Dec 02 '14 at 05:48

9 Answers9

6

Here's a fiddle that you might like: http://jsfiddle.net/e5gwc1gq/2/

I believe that the problem is because the :before psuedo element doesn't allow access to the underlying parent-div.

The reason I think so is because if you were to replace before with after, the problem persists, but is flipped, ie, now if you click in the left, it won't work properly.

Note: You might want to add word-wrap: break-word; css rule for .content-editable, since firefox doesn't add this by default, but chrome does.

zhirzh
  • 3,273
  • 3
  • 25
  • 30
  • This got as close as I could get - it introduced [carat positioning quirk](http://stackoverflow.com/q/21986985/357801) (also in FF), but that is better than the previous issue. Cheers. – Unpossible Dec 02 '14 at 18:56
4

This CSS solution actually works. Caret position sets to the end, text can selected and everything works as expected.

-moz-user-select: text;
-khtml-user-select: text;
-webkit-user-select: text;
-o-user-select: text;

Tested on Firefox 35.0.1, Chrome 40.0.2214.94 m, IE 11 Here's a fiddle: http://jsfiddle.net/yam9kkbL/

2

We ran into the same issue as described in the original question. We added a handler for "click" and "keydown" for Firefox. If the box is empty and user is trying to click or type in the box, we blur it and then focus on it again.

if ($("body").hasClass("ff"))
{
    var box = $(".content-editable");
    box.on("keydown click", function(e){
        if(box.text().trim().length == 0){
            box.blur().focus();
        }
    });
}
brian17han
  • 1,239
  • 1
  • 8
  • 15
2
-moz-user-select: text !important;

Works for me... Firefox added -moz-user-select: none; as inline style

TidharPeer
  • 3,777
  • 3
  • 21
  • 32
1

Actually, the simplest solution is the following :

Set height: 16px; for the contentEditable div.

No need to add placeholder attributes, or any other complex CSS properties combinations

Regards

Vaseaa
  • 11
  • 1
1

The problem is the use of the :before. The solution is to simulate that before with other div.

Here is my solution, I show too the :before troubles with the position relative and absolute.

https://jsfiddle.net/oropesa/d8y1k7yd/

/* halara style-reset */
* { margin: 0; padding: 0; } body { margin: 1rem; background: #dfeaff; } h4 { margin: 1rem 0 0} p { font-size: .8em; color: darkgray; margin: .5rem 0 1rem; }

/* default content style */
.content-editable {
    min-height: 1.5rem;
    max-height: 4rem;
    padding: 1.5rem;
    background: white;
    border: 1px solid #bdc3c7;
}
.content-editable:focus { border-color: #3498db; outline: 0 }

/* specific content style, troubles 1 & 2 */
.content-editable.placeholder-relative:empty:before { position: relative; }
.content-editable.placeholder-absolute:empty:before { position: absolute; }

.content-editable.placeholder-relative:empty:before,
.content-editable.placeholder-absolute:empty:before {
    content: attr(placeholder);
    color: #bdc3c7;
}

.content-editable.placeholder-relative:focus:empty:before,
.content-editable.placeholder-absolute:focus:empty:before {
   color: #3498db;
   opacity: .5
}

/* solution style */
.content-wrapper {
   position: relative;
   background: white;
 }
 
.content-editable.with-ghost {
   position: relative;
   background: transparent;
   z-index: 1;
}

.ghost-placeholder {
   position: absolute;
   display: none;
   z-index: 0;
   top: 1.5rem; /*as padding*/
   left: 1.5rem; /*as padding*/
   color: #bdc3c7;
}

.content-editable.with-ghost:empty + .ghost-placeholder {
   display: block;
}
<h3>Only in firefox</h3>

<h4>Trouble 1: placeholder in before with position relative</h4>
<p>If you click several times inside the div (not on the placeholder-text), the cursor change between the left and right part of the div (and still focused). When the cursor is on the right, typing doesn't work.</p>
<div class="content-editable placeholder-relative" contenteditable="true" placeholder="Type something here..."></div>

<h4>Trouble 2: placeholder in before with position absolute</h4>
<p>When the div is focus and empty, the cursor ignores the padding of the div. And if you click on the text the focus event is ignored.</p>
<div class="content-editable placeholder-absolute" contenteditable="true" placeholder="Type something here..."></div>

<h4>Solution:</h4>
<p>Don't use <i>:before</i> and simulate the placeholder (see the <i>html</i> and <i>css</i> code).</p>
<div class="content-wrapper">
    <div class="content-editable with-ghost" contenteditable="true" placeholder="Type something here..."></div>
    <div class="ghost-placeholder">Type something here...</div>
</div>

<h4>Another trouble (more? damn firefox...)</h4>
<p>In all cases, when you write and remove all the text, the content-editable div isn't empty, inside it has <i>&lt;br&gt;&lt;br&gt;</i>, so if you want to show the placeholder you have to remove this rubbish with javascript (on the <i>blur</i> event).</p>

<p>Good luck! =)</p>
0

I've come up with a fiddle that seems to work... the only problem is the text needs to be manually cleared.

Fiddle

HTML

<div class="content-editable" form-textarea font-face-frank
    placeholder="Type something here..." contenteditable="true"
    ng-model="form.message" ng-class="form.fontName" strip-br="true" required></div>

CSS

.content-editable {
    outline-width: 0;
    min-height: 1em;
    max-height: 300px;
    line-height: 1em;
    overflow-y: scroll;
    font-size: 44px;
    padding: 10px;
    border: 1px solid cyan;
}

JavaScript

document.getElementsByClassName('content-editable')[0].innerHTML=document.getElementsByClassName('content-editable')[0].getAttribute('placeholder');
Community
  • 1
  • 1
Timtech
  • 1,224
  • 2
  • 19
  • 30
0

The problem of :before (or :after) pseudoelement intercepting focus of contenteditable in FireFox can be solved by briefly focusing any other element and returning the focus back:

if(/firefox/i.test(navigator.userAgent))                   // Fix FireFox only
    $('span[contenteditable]').on('click', function() {    // Patch affected controls
        $('input:visible')[0].focus();                     // Focus on any other control
        this.focus();                                      // Focus back
    });

You might need to introduce this mock input to transfer focus to.

Y.B.
  • 3,526
  • 14
  • 24
0

like seems FF doesn't work correctly with ::before/after pseudo-elements.even if I set absolute positioning the new bug appeared - a caret set on the top, above the placeholder.

so my solution was to use a span (in my case - after the contenteditable div), but you can also put it inside. css will be something like:

//imitate placeholder
[contentEditable="true"] + .chat-placeholder {
  color: rgba(63, 52, 52, 0.5);
  position: absolute;
  display: none;
}

// show placeholder if the field is empty only 
[contentEditable="true"]:empty + .chat-placeholder {
  display: inline-block;
}