Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CSS on :focus within child of contenteditable

I am trying to detect focus on a child element of a contenteditable element, for the purposes of pure CSS styling. (I know I could detect this with JS, add an extra class and do it that way, but that is so long-winded.)

Basically, I have something along the lines of:

<div contenteditable="true">
  Some text <span class="edit">that</span> goes here.
</div>

I tried CSS along the lines of:

.edit:focus {
  color: #FF0000;
}

I want that span to change colour when the caret enters it, but apparently the focus is only applied to the div set to contenteditable, not to any child thereof. I have tried applying a second contenteditable to the span, but besides being a horribly sloppy approach, it doesn't work anyway.

Is there a solution to this?

like image 846
Rick Avatar asked Apr 30 '15 09:04

Rick


3 Answers

Because of the limitation that elements within a contenteditable element can't generally receive focus, I suggest faking it by adding a class to your <span> element when the selection is contained within it, which you can do by monitoring the selection for changes (you'll have to use mouse and keyboard events and polling for thoroughness in Firefox until the selectionchange event is implemented in that browser).

var selectionContainer = null;

function updateSelectionContainer() {
  var newSelectionContainer = null;
  var sel;
  if (window.getSelection && (sel = window.getSelection()).rangeCount) {
    newSelectionContainer = sel.getRangeAt(0).commonAncestorContainer;

    // Ensure we have an element rather than a text node
    if (newSelectionContainer.nodeType != 1) {
      newSelectionContainer = newSelectionContainer.parentNode;
    }
  }
  if (newSelectionContainer != selectionContainer) {
    if (selectionContainer) {
      selectionContainer.className = selectionContainer.className.replace(/ ?containsSelection/, "");
    }
    if (newSelectionContainer) {
      newSelectionContainer.className +=
        (newSelectionContainer.className ? " containsSelection" : "containsSelection");
    }
    selectionContainer = newSelectionContainer;
  }
}

if ("onselectionchange" in document) {
  document.onselectionchange = updateSelectionContainer;
} else {
  var el = document.getElementById("editor");
  el.onmousedown = el.onmouseup = el.onkeydown = el.onkeyup = el.oninput = updateSelectionContainer;
  window.setInterval(updateSelectionContainer, 100);
}
div {
  font-size: 200%;
}

.edit.containsSelection {
  color: red;
  font-weight: bold;
}
<div contenteditable="true" id="editor">
  Some text <span class="edit">that</span> goes here.
</div>
like image 163
Tim Down Avatar answered Oct 29 '22 12:10

Tim Down


My understanding is that the type of elements that can receive focus (automatically) is limited.

See SO Question

One option is to add tabindex to the span.

body {
  font-size: 3rem;
}
div[contenteditable=true] .edit:focus {
  color: #FF0000;
}
<div contenteditable="true">Some text <span class="edit" tabindex="0">that</span> goes here.</div>
like image 31
Paulie_D Avatar answered Oct 29 '22 13:10

Paulie_D


:focus > .edit { color: #cc0000; }

<div contenteditable="true">Some text <span class="edit">that</span> goes here.</div>
<div contenteditable="true">Some text that goes here.</div>
like image 2
Navneet Panchariya Avatar answered Oct 29 '22 14:10

Navneet Panchariya