How can I fix this content editable section in a Next app where content is RTL though set to LTR?

60 Views Asked by At

I'm working on a rich text editor in React/NextJS where I use a contentEditable div. I have a function updateContent that sanitizes the HTML content of this div using DOMPurify and then updates the innerHTML. However, after implementing this function, the text entered in the editor appears in reverse order. For example, typing "Hello" results in "olleH".

  // Function to update and sanitize the content
  const updateContent = useCallback(() => {
    if (!editableRef.current) return;

    // Save the current selection
    const selection = window.getSelection();
    let savedRange = null;
    if (selection && selection.rangeCount > 0) {
      const range = selection.getRangeAt(0);
      savedRange = {
        startContainer: range.startContainer,
        startOffset: range.startOffset,
        endContainer: range.endContainer,
        endOffset: range.endOffset,
      };
    }

    // Sanitize and update the content
    const rawHtmlContent = editableRef.current.innerHTML;
    const sanitizedContent = DOMPurify.sanitize(rawHtmlContent, {
      ADD_TAGS: ["iframe"],
      ADD_ATTR: ["allowfullscreen", "frameborder", "src"],
    });
    editableRef.current.innerHTML = sanitizedContent;

    // Restore the cursor position
    if (savedRange) {
      const newRange = document.createRange();
      newRange.setStart(savedRange.startContainer, savedRange.startOffset);
      newRange.setEnd(savedRange.endContainer, savedRange.endOffset);
      selection.removeAllRanges();
      selection.addRange(newRange);
    }

    setContent(sanitizedContent);
    onContentChange(sanitizedContent);
    setIsCodeMode(sanitizedContent.includes("<pre>"));
  }, [editableRef, onContentChange]);

I have a feeling this has to do with the insertion of content updating too frequently, but all of the fixes I've tried haven't worked and am having trouble finding anything helpful in the docs.

I've tried saving and restoring the selection range before and after updating the innerHTML.

I've tried explicitly setting the text direction in css or in the div but doesn't seem to matter. Here is the div in question.

I experimented with different methods of updating the content to avoid direct innerHTML manipulation.

Using Next 14.0.4, dompurify 3.0.8, using Chrome Version 120.0.6099.216 on M1 Mac.

<div
        ref={editableRef}
        contentEditable
        onInput={updateContent}
        dangerouslySetInnerHTML={{ __html: content }}
        onPaste={handlePaste}
        dir="ltr" 
/>
0

There are 0 best solutions below