Note: This is not a duplicate as far as I can tell, as using a contentEditable
div doesn't seem to be a good alternative. It has numerous problems (no placeholder text, need to use the dangerouslySetInnerHTML
hack to update text, selection cursor is finicky, other browser issues, etc.) I would like to use a textarea.
I'm currently doing something this for my React textarea component:
componentDidUpdate() {
let target = this.textBoxRef.current;
target.style.height = 'inherit';
target.style.height = `${target.scrollHeight + 1}px`;
}
This works and allows the textarea to dynamically grow and shrink in height as line breaks are added and removed.
The problem is that on every text change there is a reflow occurring. This causes a lot of lag in the application. If I hold down a key in the textarea there is delay and lag as the characters are appended.
If I remove the target.style.height = 'inherit';
line the lag goes away, so I know it's being caused by this constant reflow.
I heard that setting overflow-y: hidden
might get rid of the constant reflow, but it did not in my case. Likewise, setting target.style.height = 'auto';
did not allow for dynamic resize.
I currently have developed a solution to this which works, but I don't like it, as it is an O(n) operation for every time the text changes. I just count the number of line breaks and set the size accordingly, like this:
// In a React Component
handleMessageChange = e => {
let breakCount = e.target.value.split("\n").length - 1;
this.setState({ breakCount: breakCount });
}
render() {
let style = { height: (41 + (this.state.breakCount * 21)) + "px" };
return (
<textarea onChange={this.handleMessageChange} style={style}></textarea>
);
}
debounce
with a wait of 166ms, so it doesn't reflow constantly. And the hidden "shadow"<textarea>
. – Stallardtarget.style.height
) – Mut