What you are trying to achieve is a very old trick. I have used it myself but trying a different approach.
It makes more sense why the text area is jumpy coz every keystroke you were making the height = 0
to calculate scroll height so that you can assign a new height.
I calculated the fontSize or lineHeight and calculated number of lines and the initial height to adjust based on that. So on every keystroke you are just assigning height w/o making the text area height=0
textareaProps = null;
getHeight(element) {
const lines = element.value.split(/\r\n|\r|\n/).length;
if(!this.textareaProps) {
const autoStyle = getComputedStyle(element);
const lineHeight = parseInt(autoStyle.lineHeight);
const adjust = parseInt(autoStyle.height) - lineHeight;
this.textareaProps = {adjust, lineHeight}
}
const { adjust, lineHeight } = this.textareaProps;
const height = lines * lineHeight + adjust;
return height + 'px';
}
You now need to call this method to get height and pass the textarea element as arg.
element.style.cssText = 'height:' + getHeight(element) ;
Edit 2
Sadly the above solution will only work if there are line breaks by user. When you enter a huge line text area wraps it but it doesn't increase the height. So intruducing a proxy html element which will have the text as same as text area value and will provide a height that we can assign to our text area.
textareaProps = null;
getHeight(element) {
if(!this.textareaProps) {
const proxy = document.createElement('div');
const {padding, width, fontSize, height, lineHeight} = getComputedStyle(element);
const css = [
'position:absolute',
'visibility: hidden',
'pointer-events:none',
`width: ${width}`,
`padding:${padding}`,
`min-height: ${height}`,
`font-size:${fontSize}`,
`line-height:${lineHeight}`,
].join(';');
proxy.style.cssText=css;
this.textareaProps = {
proxy: document.body.appendChild(proxy),
adjust: (parseInt(fontSize))
};
}
const { proxy, adjust} = this.textareaProps;
proxy.innerText = element.value + '.';
return (proxy.offsetHeight + adjust) + 'px';
}
Updated StackBlitz https://stackblitz.com/edit/next-line-view-child-ssnp4q
<textarea>
element must be resized. Having amin-height
would prevent this issue. You can see it live on StackBlitz. But when cursor reaches last line, entering more text would result in resizing and the same issue repeats. – Keikokeilmin-height
andmax-height
to avoid this issue altogether. You will get a scrollbar in the textarea instead of an ever-expanding element. See it live on StackBlitz. – Keikokeil