How can I prevent my cursor from jumping to the beginning of a contentEditable div onInput in React?

208 Views Asked by At

I'm trying to create a small text editor with React. For now I only need one feature: syntax highlighting.

The problem is absurd: onInput the cursor moves to the beginning of the div.

For obvious reasons I cannot use a textarea, so I need a div with contentEditable attribute.

I then tried onInput moving the cursor after the typed character, but without success.

So, if I understand correctly, either I give up contentEditable or I give up dangerouslySetInnerHTML. Or I give up the onInput handler.

But without these elements I don't see any alternative....

Below is the code produced so far

const EditableElement = () => {
    const keywords = [
        "def",
        "if",
        "else",
        "elif",
        "for",
        "while",
        "try",
        "except",
    ];

    const [text, setText] = React.useState("");
    const elementRef = React.useRef(null);

    const handleChange = () => {
        const value = elementRef.current.innerText;
        setText(value);
    };

    const highlightKeywords = () => {
        let highlightedText = text;
        keywords.forEach((keyword) => {
            const regex = new RegExp(`\\b(${keyword})\\b`, "g");
            highlightedText = highlightedText.replace(
                regex,
                `<span class="keyword">$1</span>`
            );
        });
        return highlightedText;
    };

    React.useEffect(() => {
        const html = highlightKeywords();
        elementRef.current.innerHTML = html;
    }, [text]);

    return (
        <div
            className="code-editor"
            placeholder="Write your Python code here..."
            contentEditable
            suppressContentEditableWarning
            onInput={handleChange}
            ref={elementRef}
            dangerouslySetInnerHTML={{ __html: highlightKeywords() }}
        />
    );
};```
1

There are 1 best solutions below

0
On

By using dangerouslySetInnerHTML your content gets re-rendered on every state change. Because of that, your element loses the cursor position. In order to keep the cursor position you'll need to manipulate the DOM directly (update selection etc.).

As others have already suggested, you probably don't want to go that path. There are good solutions out there.