Unable to move cursor in contenteditable section

I am currently working on developing a rich text editor in React, but I have encountered an issue that has me stuck. The problem I am facing is that as I type each character, the insertion point does not update accordingly, causing the cursor to remain stuck on the left side while new characters are being inserted at the leftmost position. Furthermore, when I manually move the cursor to the end of a word and try typing again, it unexpectedly shifts back to the left.

You can view a screenshot of my text editor here.

import React from "react";
import { useState } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
  faBold,
  faCode,
  faFileCode,
  faFilm,
  faImage,
  faItalic,
  faLink,
  faList,
  faListOl,
  faQuoteRight,
  faStrikethrough,
  faUnderline,
} from "@fortawesome/free-solid-svg-icons";
import "./textEditor.css";

// Rest of the JavaScript code...

CSS

.editor-wrapper {
  width: 100%;
  height: 500px;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.editor {
  width: 70%;
  // Additional styling properties...
}

Answer №1

To address this issue, I introduced a new function that directs the cursor's focus towards the user by utilizing the useEffect hook with a listener attached to the content hook. Here is how the function works:

function focus() {
  const contentEle = document.getElementById('content');
  const range = document.createRange();
  const selection = window.getSelection();
  range.setStart(contentEle, contentEle.childNodes.length);
  range.collapse(true);
  selection.removeAllRanges();
  selection.addRange(range);
}

useEffect(() => {
  focus();
}, [content]);

This code now includes the newly created function.

// Importing necessary dependencies
import React from "react";
import { useState, useEffect } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
  faBold,
  faCode,
  faFileCode,
  faFilm,
  faImage,
  faItalic,
  faLink,
  faList,
  faListOl,
  faQuoteRight,
  faStrikethrough,
  faUnderline,
} from "@fortawesome/free-solid-svg-icons";
import "./textEditor.css";

const TextEditor = () => {
  // State hooks declaration
  const [content, setContent] = useState("");
  const [isBold, setIsBold] = useState(false);
  const [isItalic, setIsItalic] = useState(false);
  const [isUnderline, setIsUnderline] = useState(false);
  const [isStrikeThrough, setStrikeThrough] = useState(false);
  const [isBlockquote, setIsBlockquote] = useState(false);
  const [isHeading1, setIsHeading1] = useState(false);
  const [isHeading2, setIsHeading2] = useState(false);
  const [isOrderedList, setIsOrderedList] = useState(false);
  const [isUnorderedList, setIsUnorderedList] = useState(false);
  const [isInlineCode, setIsInlineCode] = useState(false);
  const [isCodeBlock, setIsCodeBlock] = useState(false);

  // Function to handle text formatting
  const handleFormat = (style, value = null) => {
    // Toggling state for corresponding style
    switch (style) {
      case "bold":
        setIsBold(!isBold);
        break;
      case "italic":
        setIsItalic(!isItalic);
        break;
      case "underline":
        setIsUnderline(!isUnderline);
        break;
      // Other cases omitted for brevity
    }

    // Applying the selected style
    document.execCommand(style, false, value);
  };

  // Defining the focus function
  function focus() {
    const contentEle = document.getElementById('content');
    const range = document.createRange();
    const selection = window.getSelection();
    range.setStart(contentEle, contentEle.childNodes.length);
    range.collapse(true);
    selection.removeAllRanges();
    selection.addRange(range);
  }

  // Triggering focus on content change
  useEffect(() => {
    focus();
  }, [content]);

  return (
    <!-- Component structure and button implementations here -->
  );
};

export default TextEditor;

For more details and to access the updated project with this solution, you can visit the following link: https://github.com/pablosalazzar/stackoverflow-answer-2

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Angular: promptly exit out of ngClick event handler

I have a selection menu on my webpage that is essentially an unordered list, with each item in the menu formatted like this: <li ng-click='doCalc(5)'>Five</li> The doCalc function that is triggered by clicking on these items may tak ...

What could be causing jQuery document ready to restrict access to global variables?

Currently, I am working on a project that involves three separate JavaScript files (example1.js, example2.js, and example3.js) being scripted into a single HTML file (index.html). These JS files are responsible for making an API call and manipulating the r ...

Navigate to a different page using an AJAX request

Is it possible to use ajax for redirecting to another page? Here's the code I've been working on: <script type="text/javascript"> $(document.body).on('click', '#btnPrintPrev', function() { $.ajax({ url: &apo ...

What is the best way to utilize context within the main layout of the Next 13 application directory?

I am looking to apply my global theme to style the body in the RootLayout of the new Next 13 app directory. How can I implement a context within that root layout? import './globals.css' import { Inter } from 'next/font/google' import T ...

Issue with jQuery: Changes are not being triggered and clicks are also not working

I managed to recreate the modifications of my complex script in a simple jsfiddle, which can be found here. Below is the code I am working with locally: HTML <input type="text" id="rangeStart" value="updateMe" /><br/> <input type="text" c ...

Display an AJAX div when the image is hovered over and have it track the movement of

I am seeking assistance with my website project, which involves providing users with download links to movies. However, I am struggling to make the preview_block div(id) appear when the mouse hovers over the movie_block div(id). Additionally, I am having ...

I'm wondering why using display flex with justify-content center and align-items center is not properly centering the elements both horizontally and vertically. Can anyone explain this?

As I delve into the world of JavaScript, I find myself coding simple JS, HTML, and CSS snippets to enhance my learning experience. These exercises help me grasp the concepts well enough to create various JS web elements and projects. My goal is to eventual ...

The bullets in the HTML unordered list are partially hidden from view

My unordered list is experiencing issues with displaying bullets correctly. In Firefox and Internet Explorer, the bullets are only partially shown, while in Chrome they are not visible at all. Adding margin-left: 5px to the <li> element resolves this ...

The data being rendered twice in React-Native due to Array.map

Currently, I am encountering an issue in my React Native application where the data in an array is being rendered twice by a component, resulting in an exception being thrown. I received a warning stating: Each child in a list should have a unique "key" ...

What is the best way to identify a video or image from a URL and showcase it seamlessly in one tag with the help of React and Material UI

I need some advice on a project I'm working on. I want to create a Cover section for a profile page that allows users to choose between setting an image or a video as their cover. I'm struggling with how to display both a video and an image file ...

The React application is unable to load the local host at port 3000

Hey there! Last Friday I was working on my react application and it was running smoothly. However, today when I tried to start it up again, the page just keeps loading (staying blank with a blue circle loading icon in the tab) or eventually shows an error ...

how to execute Vue-Js method just one time

Is there a way to add a random number (ranging from 0 to the price of an item) to one of the data properties in Vue.js, but only once when the page is initially loaded? I am unable to use mounted and computed because I need to pass a parameter to the funct ...

Sending a parameter to a request-promise function within an iteration through a forEach loop

I have successfully implemented an API call for price data. However, I am facing an issue while trying to pass the variable exchange_pair_id into the then() function. Within the forEach loop, the exchange_pair_id is accurate for each asset. But inside the ...

Unable to start react-scripts due to event.js error at line 182

I recently copied a project from bitbucket, and encountered an issue when trying to run npm start. The error message I received was: events.js:182 throw er; // Unhandled 'error' event ^ Error: watch /var/www/html/eoffice-chat-web/p ...

The custom directive in Vue utilizes the refreshed DOM element (also known as $el)

I am looking to create a custom directive that will replace all occurrences of 'cx' with <strong>cx</strong> in the Dom Tree. Here is my current approach: Vue.config.productionTip = false function removeKeywords(el, keyword){ i ...

Bottom section of a multi-level website with horizontal dividers

I was struggling with aligning divs next to each other, but I managed to find a solution. The only issue is that the text now aligns to the right instead of going below as it should. Typically this wouldn't be an issue since all content is within the ...

Creating a Sidebar with material-ui

Currently, I am working on learning material-ui and developing a navigation menu similar to examples found at or at least resembling something like this: http://www.material-ui.com/#/components/app-bar In order to create my sidebar, I am using the Drawer ...

Packages required for plugins on Npm

I am fairly new to NPM dependencies and I'm currently transitioning from the Ruby world. Working on a Chrome extension utilizing React, in my content.js script, I have the following code at the top: var React = require("react"); var $ = require("jqu ...

Tips on gathering data from the Mui date picker

On my website, I am using a date picker from MUI and I want to capture start and end dates just like we do with regular input fields. Here is the snippet of code I have: const Dates = [ { label: "From", name:"From" ,placeholder: " ...

Modify the stroke attribute of the <path> element using CSS

I have a generated svg path code that I want to customize using CSS to remove the default stroke. How can I override the stroke property and set it to none? code: <div class="container" style="position: absolute; left: 3px; z-index: 1;"> <svg he ...