Use Javascript. textarea behaves like a textarea, and you want to change that (you want it to behave like a div), so you have to hack in the behavior you want.
Here's a solution I found somewhere a few months ago but have not been able to find again. It may have my own flavor added in:
Markup:
<div>
<textarea class='my-textarea' />
<div className='my-textarea autogrow' style="display: 'none';" />
</div>
Styles:
.my-textarea {
border: 1px solid #bbb;
font-family: Helvetica;
font-size: 15px;
overflow: hidden;
padding: 5px;
resize: none;
}
// Needs same styles as the textarea except overflow.
.autogrow {
overflow: auto !important;
}
Get this event listener onto the textarea's change
event:
function growTextarea(e) {
const { value } = e.target
const textarea = e.target
const { grower } = this
grower.style.display = 'block'
grower.innerHTML = value.length ? value : 'x'
textarea.style.height = grower.offsetHeight + 'px'
grower.style.display = 'none'
}
How does it work? Basically a div's expansion is what you want the textarea's expansion to behave like. So you're making a div with all the same styles as the textarea and putting the textarea's value into the div. Then you get the div's height and set the textarea's height to that.
Using display none and block, the div appears and disappears so you can measure its height. You'll never actually see it in the browser.
Hope this works for you!
P.S. I use React so I had to change my solution to be framework agnostic. So it may have bugs or syntax errors. E.g. you might have to query the document to find the grower div.