React: Unable to set scrollTop on a Div under certain conditions

I've been grappling with this issue since this morning and I still can't pinpoint where I went wrong. My goal was to highlight text within a textarea input, even though I know it's not technically possible. However, I came across a clever workaround that tricks the viewer into thinking it is. You can find the article here and the codePen project here.

I've attempted to replicate the same functionality using React and regular JavaScript, but I'm having trouble with the scrollTop property for the div with the className 'highlight'. If anyone could assist me in troubleshooting what I might be doing incorrectly, I would greatly appreciate it!

class CodeTextArea extends React.Component {
  constructor(props){
    super(props);
    this.state = {scrollTop: 0, 
                  scrollLeft: 0
                 };
    this.setScroll = this.setScroll.bind(this);
  }
  setScroll(top,left){
    this.setState({scrollTop: top, scrollLeft: left});
  }
  render(){
    return(
      <div class="container">
        <div class="backdrop">
          <Highlight scrollTop={this.state.scrollTop} scrollLeft={this.state.scrollLeft}/>
        </div>
        <Textarea setScrollTop={this.setScroll}/>
      </div>
    );
  }
}
class Highlight extends React.Component {
    constructor(props){
    super(props);
    this.divRef = React.createRef();
  }
  componentDidUpdate(prevProps){
    if (this.props.scrollTop !== prevProps.scrollTop) {
      /*console.log(this.divRef.current);
      console.log(this.props.scrollTop);
      console.log(this.props.scrollLeft);*/
      this.divRef.current.scrollTop = this.props.scrollTop;
    }

  }
  render(){       
    return (
      <div class="highlights" ref={this.divRef}><mark>This</mark> demo shows how to highlight bits of text within a <mark>textarea</mark>. Alright, that's a lie. You can't actually render markup inside a textarea. However, you can fake it by carefully positioning a div behind the textarea and adding your highlight markup there. JavaScript takes care of syncing the content and scroll position from the textarea to the div, so everything lines up nicely. Hit the toggle button to peek behind the curtain. And feel free to edit this text. All capitalized words will be highlighted.
      </div>
    );
  }
}
class TogglePerspective extends React.Component {
  constructor(props){
    super(props);
    this.clickHandler = this.clickHandler.bind(this);
    this.buttonRef = React.createRef();
  }
  clickHandler(){

  }
  render(){
    return (
      <button onClick={this.clickHandler} ref={this.buttonRef}>Toggle Perspective</button>
    );
  }
}
class Textarea extends React.Component {
  constructor(props){
    super(props);
    this.handleScroll = this.handleScroll.bind(this);
    this.handleChange = this.handleChange.bind(this);
    this.applyHighlights = this.applyHighlights.bind(this);
    this.textareaRef = React.createRef();
    this.state = {value: 'This demo shows how to highlight bits of text within a textarea. Alright, that\'s a lie. You can\'t actually render markup inside a textarea. However, you can fake it by carefully positioning a div behind the textarea and adding your highlight markup there. JavaScript takes care of syncing the content and scroll position from the textarea to the div, so everything lines up nicely. Hit the toggle button to peek behind the curtain. And feel free to edit this text. All capitalized words will be highlighted.'};
  }

  applyHighlights(text){
    return text
        .replace(/\n$/g, '\n\n')
        .replace(/[A-Z].*?\b/g, '<mark>$&</mark>');
  }

  handleScroll(){
    let scrollTop = this.textareaRef.current.scrollTop;
    let scrollLeft = this.textareaRef.current.scrollLeft;
    this.props.setScrollTop(scrollTop,scrollLeft);
  }

  handleChange(event){
    let textareaValue = event.targrt.value;
    this.setState({value: textareaValue});
    let highlightedText = this.applyHighlights(textareaValue);
  }

  render(){
    return (
      <textarea ref={this.textareaRef} value={this.state.value} onChange={this.handleChange} onScroll={this.handleScroll}></textarea>
    );
  }
}
class Editor extends React.Component {
  render(){
    return (
     <div>
       <CodeTextArea />
       <TogglePerspective />
     </div>
    );
  }
}

ReactDOM.render(
 <Editor />,
 document.getElementById('root')
);

Here is the codeIo pen to my recreation. Can someone please help me figure out why the scrollTop attribute of the 'highlight' class div isn't functioning correctly? I typically don't post lengthy code like this unless I'm truly at a loss, so any assistance would be valued.

Answer №1

It seems like there is a mistake in setting the scrollTop property on the div.highlights element instead of the div.backdrop element.

To fix this, move the div.backdrop element into the Highlight Component and add the reference to that element:

<div class="backdrop" ref={this.divRef}>
<div class="highlights">
    <mark>This</mark> demo shows how to highlight bits of text within a <mark>textarea</mark>.
    Alright, that's a lie. You can't actually render markup inside a textarea. However, you can 
    fake it by carefully positioning a div behind the textarea and adding your highlight markup there. 
    JavaScript takes care of syncing the content and scroll position from the textarea to the div, so everything lines up nicely. 
    Hit the toggle button to peek behind the curtain. And feel free to edit this text. All capitalized words will be highlighted.
</div>

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

Open the application through the web browser; if it can't be found, direct to the app store

Looking for a solution for my application that uses a webview to make references to other applications. Here's what I need: -If the referenced application is installed, it should launch it -If the referenced application is not installed, it should p ...

What is the reason behind the varying dimensions of images on Chrome compared to Firefox?

I've been working on enhancing my web development skills and decided to create a personal portfolio. During the development process, I focused mainly on Firefox as my browser of choice. One section of the portfolio includes showcasing my skills using ...

Having trouble getting the Babel plugin transform-remove-console to function properly with the Vue CLI 4 and @vue/cli-plugin-babel/preset?

When you create a VueJS project using Vue CLI 4, Babel is configured with a useful preset in babel.config.js: module.exports = { presets: [ '@vue/cli-plugin-babel/preset', ], }; I am attempting to use babel-plugin-transform-remove-conso ...

Using JQuery to swap out all URLs on a webpage?

Seeking guidance and examples on replacing all the links in the head of a document using jQuery. I am currently working with an app that requires my site to have SSL. To address this requirement without purchasing an SSL certificate or a static IP, I am a ...

Testing of AngularJS Controller using Jasmine and Karma: "Error - Unable to read property 'then' of undefined"

I am currently attempting to perform unit testing on an AngularJS controller and encountering an error message while running Karma: Cannot read property 'then' of undefined I am unsure of what I am doing incorrectly. This is my first time con ...

The function str.split() is dividing the text based on individual letters rather than the specified delimiter

I am facing an issue where the string of tags retrieved from firebase needs to be split by ',' and stored in the data() for rendering. The firebase snapshot data is correctly formatted after splitting when viewed in the console like this: "t ...

The modal feature is malfunctioning on a dynamic Flask website across all web browsers

I've encountered a peculiar issue while developing a Flask website that involves the functionality of a Bootstrap modal. This problem is consistent across different browsers like Firefox, Chrome, and Safari. On the main route of my website, users can ...

Searching for data in Node.js using Mongoose and dates

I'm in search of a way to execute a specific query with mongoose. In my mongodb database, I have data structured like this: "startDateTime" : ISODate("2017-03-22T00:00:00.000Z"), "endDateTime" : ISODate("2017-03-27T00:00:00.000Z"), My goal is to r ...

Implementing Dynamic Checkbox Selection using JavaScript

Could someone please assist me with this coding challenge? HTML <div id="toggle"> <ul> <li class="active"><input type="checkbox" id="test" value="2014" name="test" checked/> 2014</li> <div style="display:block;" id ...

Is it possible with jQuery UI Autocomplete to load search results into a designated div?

Currently in the process of switching from YUI to jQuery, I'm facing a challenge in loading autocomplete results into a specified container like a div. My goal is to dynamically populate a div with styled search results, which may include images asso ...

Ways to generate an Angular 7 component

Seeking guidance on creating an angular 7 component. I have forked a jsFiddle at this link: https://jsfiddle.net/gauravshrestha/fdxsywLv/. The chart in the fiddle allows data points to be dragged up and down. My goal is to convert this into a component whe ...

Conceal the object, while revealing a void in its place

Is there a way to hide an image but keep the containing div blank with the same dimensions? I want it to appear as if no content was there, maintaining the original width and height. For example: http://jsfiddle.net/rJuWL/1/ After hiding, "Second!" appea ...

Is there a way to include a different component without it automatically displaying within a div element?

Is there a way to make the Torrent component render without directly binding it to a DOM element? I am facing an issue with my Torrent Table Component as I want it to be populated with Torrent Components based on API data, but it's not rendering beca ...

The process of retrieving an array and saving it in the state with React Native Hooks

I am attempting to fetch an array and update state using hooks const [items, setItems] = useState([]); const getItems = async () => { try { const response = await apiLink.get('...'); const data = response.data; co ...

How about: "Transmitting JSON to a webmethod?"

Is there a way to utilize jQuery to send a JSON object to a webmethod? ...

Leveraging the power of the wildcard feature to execute a variety of scripts when running

Inside my package.json file, I currently have the following scripts block: "scripts": { "test": "node tests/*-test.js" } In the tests folder, I have files named a-test.js and b-test.js. This can be confirmed by using the command ls tests/*-test.js. ...

Encountering an issue while attempting to convert a string into JSON from a .json file within a Node.js environment

var jsonObject = collages; file.writeFile('collage.json', JSON.stringify(jsonObject), function(err){ if (err) throw err; console.log('Success'); }); var result = ''; result += file.readFile('collage.json', ...

Passport and Node.js team up to create powerful user group functionalities

Seeking advice on this topic. I am interested in setting up a page with a login form as the main page. Upon logging in, users would be directed to their personalized dashboard. However, if someone logs in with admin privileges, they should be redirected t ...

Building a custom CellRenderer in AGGrid using TypeScript within a React environment

Currently, I am utilizing React along with TypeScript and attempting to create a custom CellRenderer in AGGrid. My code is structured like this: PriorityCellRenderer.tsx import React from 'react'; function PriorityCellRenderer(props:any) { co ...

Ensuring Property Security with Sequelize JS

var Game = sequelize.define('Game', { secretField: { type: DataTypes.STRING(45), validate: { notEmpty: true } } }, { getterMethods: { secretFieldHash: function () { return cryp ...