<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: wlto</title>
    <description>The latest articles on DEV Community by wlto (@wlto).</description>
    <link>https://dev.to/wlto</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F333530%2Fd08ce61e-0889-44ff-aea0-41a4f0385907.PNG</url>
      <title>DEV Community: wlto</title>
      <link>https://dev.to/wlto</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/wlto"/>
    <language>en</language>
    <item>
      <title>create an auto-expanding textarea with just javascript</title>
      <dc:creator>wlto</dc:creator>
      <pubDate>Mon, 11 Nov 2024 17:26:12 +0000</pubDate>
      <link>https://dev.to/wlto/create-an-auto-expand-textarea-with-just-javascript-4jp8</link>
      <guid>https://dev.to/wlto/create-an-auto-expand-textarea-with-just-javascript-4jp8</guid>
      <description>&lt;p&gt;in this tutorial, i'll show you how to create a textarea component that satisfies these requirements:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;auto-expands as the user types (ie. growing in height).&lt;/li&gt;
&lt;li&gt;is accessible.&lt;/li&gt;
&lt;li&gt;works with “textwithnowhitespaceinbetweenlikethisone”.&lt;/li&gt;
&lt;li&gt;works with any font.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;the solution i'm proposing does not require any extra javascript library. keep in mind the constraints above as we go through this together.&lt;/p&gt;

&lt;h2&gt;
  
  
  the idea
&lt;/h2&gt;

&lt;p&gt;the idea is that we would like to calculate the final height of the &lt;code&gt;textarea&lt;/code&gt; as the user types in each keystroke. here is an illustration:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3bx5ks82bf6kxawum2by.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3bx5ks82bf6kxawum2by.png" alt="Screenshot 1" width="800" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;to do this, it's crucial to know how many lines there are in the current text when compared to the &lt;code&gt;textarea&lt;/code&gt;'s height, which includes its padding, top and bottom border width (if any).&lt;/p&gt;

&lt;p&gt;let's first establish the html and css code for this &lt;code&gt;textarea&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffs2yi9ouac98s19qpiva.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffs2yi9ouac98s19qpiva.png" alt="Screenshot 2" width="800" height="1365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;there's a few things to pay attention to here:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;essential values&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;as noted in the code comment, some css values are going to be used in javascript so that we can calculate the final height of the textarea. these values are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;line height&lt;/li&gt;
&lt;li&gt;top and bottom paddings&lt;/li&gt;
&lt;li&gt;top and/or bottom border width&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fop4gfsh027in84usw04f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fop4gfsh027in84usw04f.png" alt="Screenshot 3" width="800" height="204"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;in this example, for simplicity, i will just be duplicating those values in javascript by creating constants that have the same values. of course, you can also just get those values in javascript as well if you'd prefer, using something like &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle" rel="noopener noreferrer"&gt;&lt;code&gt;window.getComputedStyle&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;box-sizing&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;for this to work, we need to set &lt;code&gt;box-sizing&lt;/code&gt; to &lt;code&gt;border-box&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;rows&lt;/code&gt; attribute&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;notice that i've set the &lt;code&gt;rows&lt;/code&gt; attribute of the &lt;code&gt;textarea&lt;/code&gt; to &lt;code&gt;1&lt;/code&gt;. this resets the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea#rows" rel="noopener noreferrer"&gt;default number of rows&lt;/a&gt; that is applied to &lt;code&gt;textarea&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  the juicy part
&lt;/h2&gt;

&lt;p&gt;now let's go into the juicy part - javascript.&lt;/p&gt;

&lt;p&gt;let's first duplicate those essential CSS values inside our &lt;code&gt;script&lt;/code&gt; tag.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fao9y6m4u3k8id92frgkr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fao9y6m4u3k8id92frgkr.png" alt="Screenshot 4" width="800" height="351"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;then, let's query the &lt;code&gt;textarea&lt;/code&gt; element and add an event listener to it. this will allow us to detect the &lt;code&gt;input&lt;/code&gt; event as the user types into the textarea.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgzqcu0oc5gcdpwn4qs48.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgzqcu0oc5gcdpwn4qs48.png" alt="Screenshot 5" width="800" height="496"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;then, if we run the code on our web browser, we will start seeing some logs as we type into the text box.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhdzwe9zgizkx3h95ygxy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhdzwe9zgizkx3h95ygxy.gif" alt="Screenshot 6" width="800" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;we don't want our textarea to be resizable, since by the end of this tutorial, we would have an auto-resize textarea. so let's set its &lt;code&gt;resize&lt;/code&gt; css attribute to &lt;code&gt;none&lt;/code&gt; in javascript.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh9fgy9c583zseahy5thn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh9fgy9c583zseahy5thn.png" alt="Screenshot 7" width="800" height="516"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;the reason why we want to do it in javascript and not css is because we want to allow users who disable javascript to be able to use our &lt;code&gt;textarea&lt;/code&gt; field like usual.&lt;/p&gt;

&lt;h2&gt;
  
  
  final steps
&lt;/h2&gt;

&lt;p&gt;now, the question is, how do we calculate the final height of a textarea element that doesn't have pre-determined content?&lt;/p&gt;

&lt;p&gt;we need a few pieces of information:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;what is the actual height of the content that is entered, excluding all the paddings and borders?&lt;/li&gt;
&lt;li&gt;how many lines of content have been entered?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;as you might know, whenever we enter text into a &lt;code&gt;textarea&lt;/code&gt; element, if the content ends up overflowing the element's pre-set height, it will and should be scrollable. this allows the user to see the overflowing content. we need to use this scrollable height value to determine the height of the content that is being entered.&lt;/p&gt;

&lt;p&gt;luckily, the browser has something built in that can help us with that. and it is &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight" rel="noopener noreferrer"&gt;&lt;code&gt;Element.scrollHeight&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj4ll31wahxu9qp696ivn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj4ll31wahxu9qp696ivn.png" alt="Screenshot 8" width="800" height="305"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;with this information, we can calculate the actual height of the content. dividing that value by the &lt;code&gt;textarea&lt;/code&gt;'s line height, and we will get the number of lines.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgiwudjmtethtotuvpc2l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgiwudjmtethtotuvpc2l.png" alt="Screenshot 9" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and it is working as expected.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fewo9ufptn2v8661vlfry.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fewo9ufptn2v8661vlfry.gif" alt="Screenshot 10" width="800" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;finally, we can calculate the final height of the &lt;code&gt;textarea&lt;/code&gt; using this formula below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;extra_vertical_spacing = top_padding + bottom_padding + top_border_width + bottom_border_width
final_height = (number_of_lines x line_height) + extra_vertical_spacing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;however, in my example, i only have top padding, bottom padding and bottom border width. hence, my code becomes this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faarnjhvtl3l9a6ic7nst.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faarnjhvtl3l9a6ic7nst.png" alt="Screenshot 11" width="800" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and we can set the calculated height value back to &lt;code&gt;textarea&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F09j2hmirx8gw7a3b93rs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F09j2hmirx8gw7a3b93rs.png" alt="Screenshot 12" width="800" height="641"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;at this point, this is our result.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnodac9yfdhnrd11bidpc.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnodac9yfdhnrd11bidpc.gif" alt="Screenshot 13" width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;it seems to work fine. but what happens if we delete our text and the number of lines reduces?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa7z8r95lexuqxab6xr6u.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa7z8r95lexuqxab6xr6u.gif" alt="Screenshot 14" width="800" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;you'll see that there is a bug here. it seems like our &lt;code&gt;textarea&lt;/code&gt; is not automatically re-adjusting its height after we delete our text.&lt;/p&gt;

&lt;p&gt;when we delete our text, &lt;code&gt;scrollHeight&lt;/code&gt; does not change. as detailed in &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight" rel="noopener noreferrer"&gt;mozilla's documentation&lt;/a&gt;, it's used to determine the minimum height required to fit all the content within the textarea withour scrollbar. hence, it will not decrease since it is assuming that the previous content we entered is the minimum amount of content.&lt;/p&gt;

&lt;p&gt;we can fix this behaviour by setting the &lt;code&gt;height&lt;/code&gt; property of the &lt;code&gt;textarea&lt;/code&gt; to &lt;code&gt;auto&lt;/code&gt; on each keystroke. this ensures that the height is reset before the calculated final height is applied to the text box.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ktvzj0d2lhsnadx4xv3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ktvzj0d2lhsnadx4xv3.png" alt="Screenshot 15" width="800" height="662"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;with that change, our final &lt;code&gt;textarea&lt;/code&gt; works like a charm&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgmw0ha0rtj8fsuig3g1k.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgmw0ha0rtj8fsuig3g1k.gif" alt="Screenshot 16" width="800" height="414"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;thank you for reading!&lt;br&gt;
wlto&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
