3

I do not wish to move the cursor, anywhere but when I call the function focus, it moves the cursor to the beginning. I wish to keep the cursor where it is. I am doing this in ReactJS using Typescript.

const element = document.getElementById('editable-div');
element.focus();   // sets cursor to beginning here
// rest of my code is here

I want to call focus because I need to append stuff in the contenteditable div and in some cases insert stuff. But as soon as I do focus(), it moves the cursor at the wrong place. How do I fix this?

  • Why do you require to call the ````focus```` method when you are going to only append or insert stuff? You have ````innerHTML```` for that. – Nafiz Ahmed Jun 01 '20 at 11:02
  • @NafizAhmed the insertion can be anywhere in the contenteditable div depending on the position of the cursos – Ieshaan Saxena Jun 02 '20 at 04:27

1 Answers1

0

With the help of document.createRange and Window.getSelection it is possible

const { useState, useEffect, useRef } = React;

const random = (from, to) => Math.floor(Math.random() * (to - from) + from);
const randomText = () => Array(random(5, 10)).fill(0).map((pr, index) => String.fromCharCode(index + 50)).join('')

const setCaretToTheEnd = (element) => {
  const position = element.textContent.length;
  const [childNode] = element.childNodes;
  const range = document.createRange();
  const selection = window.getSelection();
  range.setStart(childNode, position);
  range.setEnd(childNode, position);
  range.collapse(true);
  selection.removeAllRanges();
  selection.addRange(range);
}

const App = () => {
  const [text, setText] = useState('');
  const inputRef = useRef(null);
  
  useEffect(() => {
    if(inputRef && inputRef.current && text) {
      const element = inputRef.current;
            
      setCaretToTheEnd(element);
      element.focus();
    }
  }, [text]);
  
  useEffect(() => {
    let isUnmounted = false;
    let handle = null;
    
    const changeText = () => {
      setText(randomText());
    
      handle = setTimeout(changeText, 4000);
    }
    
    handle = setTimeout(changeText, 500);
    
    return () => {
      isUnmounted = true;
      clearTimeout(handle);
    }
  }, [])

  const onChange = ({target: {value}}) => setText(value);

  return <div>
    <div ref={inputRef} suppressContentEditableWarning={true} className="contentEditable" onChange={onChange} contentEditable>{text}</div>
  </div>
}

ReactDOM.render(
    <App />,
    document.getElementById('root')
  );
.contentEditable {
  padding: 1rem;
  border: 1px solid black;
}
<script src="https://unpkg.com/react/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script src="https://unpkg.com/@material-ui/core@latest/umd/material-ui.development.js"></script>
<div id="root"></div>
<script src="https://unpkg.com/material-ui-lab-umd@4.0.0-alpha.32/material-ui-lab.development.js"></script>
<div id="root"></div>
Józef Podlecki
  • 10,453
  • 5
  • 24
  • 50
  • 1
    Hey, the intent is not always to send the Caret at the end. Let's say the user goes back and figures he wants to add something in the middle as well, so, it shouldn't set the Caret to the end position. – Ieshaan Saxena Jun 02 '20 at 04:29
  • Then you can extend the function and move the caret whereever you want – Józef Podlecki Jun 02 '20 at 10:11
  • How do I get back the caret position before I call `element.focus()`? Because as soon as I call `focus` the caret moves back to the beginning, and the caret position is lost and I don't know where to move the caret. – Ieshaan Saxena Jun 03 '20 at 04:44
  • [There is question already for that](https://stackoverflow.com/questions/4928586/get-caret-position-in-html-input) – Józef Podlecki Jun 03 '20 at 10:00