Auto-Growing Textarea with Tailwind CSS
I really enjoy building user interfaces with CSS, it lets me do almost anything I want. However, at times, it can be frustrating when common functionalities are not natively supported. For example, there’s currently no built-in feature in CSS that allows me to adjust the height of a textarea based on its content. There is ongoing discussion about introducing a field-sizing property in CSS, but it is still in the early stages.
So, if you want a textarea that gets taller as more text is added, you have to use JavaScript or a simple CSS trick like the one I’m about to show you.
The idea comes from Stephen Shaw, and it’s very simple: you nest the textarea within another element configured as a grid. Then, you add a pseudo-element inside it replicating the textarea content. This pseudo-element will expand to fit the content, which in turn makes the outer grid element (and therefore the textarea) expand to the same height. So, as you add more text, the textarea grows to fit it.
We’ve reproduced this trick with Tailwind CSS. To use it, take the outer div
and wrap your textarea with it. Ensure that your textarea
includes the onInput
event – it’s responsible for updating the content of the pseudo-element. Lastly, check that the padding of the textarea
and the pseudo-elements are the same, and you’re good to go!
Code
<div class=" grid text-sm after:px-3.5 after:py-2.5 [&>textarea]:text-inherit after:text-inherit [&>textarea]:resize-none [&>textarea]:overflow-hidden [&>textarea]:[grid-area:1/1/2/2] after:[grid-area:1/1/2/2] after:whitespace-pre-wrap after:invisible after:content-[attr(data-cloned-val)_'_'] after:border
"> <textarea class="w-full text-slate-600 bg-slate-100 border border-transparent hover:border-slate-200 appearance-none rounded px-3.5 py-2.5 outline-none focus:bg-white focus:border-indigo-400 focus:ring-2 focus:ring-indigo-100" name="message" id="message" rows="2" onInput="this.parentNode.dataset.clonedVal = this.value" placeholder="Your request..." required ></textarea>
</div>