Search code examples
javascriptjqueryhtmlfacebookcontenteditable

How to set the cursor in the child of a contentEditable element?


I want to know how to set the cursor in the child of an editable element. I have a content editable DIV with a SPAN inside and I want to set the cursor in the SPAN when the DIV is clicked to prevent someone typing in the DIV.

<div class="custom-input" spellcheck="true" contenteditable="true">
  "NOT HERE"
  <span data-type="text">
    "TYPE HERE"
    <br>
  </span>
</div>

I have tried to do this with .focus() in jQuery, and it works but it just highlights the SPAN and the cursor remains in the DIV.

I'm trying to make something like Facebook chat does. Facebook chat uses contenteditable elements for the chat input, and if you click anywhere in the chat box the cursor always is focused in a SPAN label that is used for the input.


Solution

  • I had to do this recently and the below is what I ended up with.

    NOTE: This will not appear to work here or on jsFiddle due the sandboxing and whatnot. Run the code on your localhost or hosted server and you'll see it works.

      $(document).ready(function() {
        var $element = $('.type-here');
                createCaretPlacer($element, false); // set cursor and select text
                createCaretPlacer($element, true, true); // set cursor at start
                createCaretPlacer($element, true, false); // set cursor at end
    
      });
    
      function createCaretPlacer($element, collapse, atStart) { 
        var el = $element[0]; // get the dom node of the given element
        el.focus(); // focus to the element
        // feature test to see which methods to use for given browser
        if (typeof window.getSelection != "undefined" && typeof document.createRange != "undefined") {
          // handle real browsers (not IE)
          var range = document.createRange(); // create a new range object
          range.selectNodeContents(el); // add the contents of the given element to the range
          if(collapse) range.collapse(atStart); // collapse the rage to either the first or last index based on "atStart" param
          var sel = window.getSelection(); // Returns a Selection object representing the range of text selected by the user or the current position of the caret.
          sel.removeAllRanges(); // removes all ranges from the selection, leaving the anchorNode and focusNode properties equal to null and leaving nothing selected.
          sel.addRange(range); // add the range we created to the selection effectively setting the cursor position 
        } 
        else if (typeof document.body.createTextRange != "undefined") {
          // handle IE 
          var textRange = document.body.createTextRange();
          textRange.moveToElementText(el);
          if(collapse) textRange.collapse(atStart);
          textRange.select();
        }
      }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <div class="custom-input" spellcheck="true" contenteditable="true">
      "NOT HERE"
      <span data-type="text" class="type-here">
        "TYPE HERE"
        <br>
      </span>
    </div>