Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chrome appears to ignore user-select in a contenteditable div

I need to make it so some elements inside a contenteditable div are not selectable, so that the user will skip over them if they try to move the caret around where they are.

The obvious solution appears to be to style these sections using user-select: none. This works really well in Firefox, but, unfortunately, completely fails in Google Chrome.

.ok {
  -webkit-user-select: text;
     -moz-user-select: text;
      -ms-user-select: text;
          user-select: text;
}

.nope {
  -webkit-user-select: none;
     -moz-user-select: none;
      -ms-user-select: none;
          user-select: none;
}
<div contenteditable="true" readonly>
  <span class="ok">One</span><span class="nope">Two</span><span class="ok">Three</span>
  <div class="nope">
    <span class="ok">One</span><span class="nope">Two</span><span class="ok">Three</span>
  </div>
  <span class="nope">One</span><span class="ok">Two</span><span class="nope">Three</span>
  <div class="nope">
    <span class="nope">One</span><span class="ok">Two</span><span class="nope">Three</span>
  </div>
</div>

Is there any way to get this to work in Chrome as well, or is it an insurmountable limitation?

like image 927
Septagram Avatar asked Feb 07 '23 18:02

Septagram


1 Answers

I've run into this issue as well and have found a decent work around. It's not pretty but it can often get the job done.

If you add contenteditable="false" along with user-select:none; then Chrome will process the CSS rule correctly. Those elements will no longer be selectable.

The main disadvantage to this (besides having to modify the HTML) is that if one adds contenteditable="false" on a wrapper div then all its children become non-editable as well. You can further nest another contenteditable="true", which will allow the nested content to be editable, but then one cannot select from the nested content to the outside content.

Ultimately, a correct implementation of the CSS rule in Chrome when contenteditable is enabled would be the best solution. (Could be intentional due to user-select spec, see comment below)

Example of solution using contenteditable="false" (not on wrapper divs).

.ok {
  -webkit-user-select: text;
  -moz-user-select: text;
  -ms-user-select: text;
  user-select: text;
}

.nope {
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
<div contenteditable="true" readonly>
  <span class="ok">One</span>
  <span class="nope" contenteditable="false">Two</span>
  <span class="ok">Three</span>
  <div>
    <span class="ok">One</span>
    <span class="nope" contenteditable="false">Two</span>
    <span class="ok">Three</span>
  </div>
  <span class="nope" contenteditable="false">One</span>
  <span class="ok">Two</span>
  <span class="nope" contenteditable="false">Three</span>
  <div>
    <span class="nope" contenteditable="false">One</span>
    <span class="ok">Two</span>
    <span class="nope" contenteditable="false">Three</span>
  </div>
</div>
like image 99
roark Avatar answered Feb 09 '23 06:02

roark