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.