<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Affection Code</title>
  <link href="http://alexstaubo.github.com/atom.xml" rel="self"/>
  <link href="http://alexstaubo.github.com/"/>
  <updated>2010-03-05T18:38:22+01:00</updated>
  <id>http://blog.purefiction.net/</id>
  <author>
    <name>Alexander Staubo</name>
    <email>alex@purefiction.net</email>
  </author>
  
    <entry>
      <title>A better way to automatically resize text areas</title>
      <link href="http://blog.purefiction.net/2009/04/29/dynamically-resized-textareas.html"/>
      <updated>2009-04-29T00:00:00+02:00</updated>
      <id>http://blog.purefiction.net/2009/04/29/dynamically-resized-textareas</id>
      <content type="html">&lt;p&gt;There are various techniques to make &lt;code&gt;textarea&lt;/code&gt; elements automatically resize themselves to accomodate their contents. Facebook, in particular, frequently uses dynamically resizing fields. Among the tricks I have seen proposed or in actual use:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Counting the number of line breaks in the text and setting the &lt;code&gt;rows&lt;/code&gt; attribute to this number. This doesn&amp;#8217;t work unless you turn off word wrapping in the text field.&lt;/li&gt;
	&lt;li&gt;Creating a hidden &lt;code&gt;div&lt;/code&gt; element having roughly the same &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; styles as the &lt;code&gt;textarea&lt;/code&gt;, populating it with the text, then measuring the element&amp;#8217;s &lt;code&gt;clientHeight&lt;/code&gt;. This doesn&amp;#8217;t work consistently because &lt;span class=&quot;caps&quot;&gt;HTML&lt;/span&gt; is wrapped text differently from &lt;code&gt;textarea&lt;/code&gt; elements, even if you sprinkle zero-width space characters across the text; the end result is that eventually, the field height will no longer correctly track the real height of the contents. This is, I believe, the trick used by Facebook.&lt;/li&gt;
	&lt;li&gt;Detecting whether the text area has scrolled and then increasing the &lt;code&gt;rows&lt;/code&gt; attribute until it no longer scrolls. I won&amp;#8217;t even comment on this one.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;None of these techniques are completely satisfactory; all of them have flaws that interfere with the user experience.&lt;/p&gt;
&lt;p&gt;After a bit of experimentation, I found a working technique that, it turns out, is so simple it can be summarized as follows: &lt;strong&gt;Create a hidden &lt;code&gt;textarea&lt;/code&gt; and track its &lt;code&gt;scrollHeight&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s how it works. The &lt;code&gt;scrollHeight&lt;/code&gt; attribute tracks the scrollable height of the element&amp;#8217;s contents, in pixels. By continually feeding the current text into the hidden text area, we can read the height and resize the visible text area. (Why use a hidden text area and not read &lt;code&gt;scrollHeight&lt;/code&gt; from the actual text area? Because &lt;code&gt;scrollHeight&lt;/code&gt; changes depending on the height of the element.) While there are few quirks that need to be accounted for, browsers actually implement &lt;code&gt;scrollHeight&lt;/code&gt; pretty consistently for text fields.&lt;/p&gt;
&lt;p&gt;First, we create a hidden text area. Then we copy whatever style attributes (font family, font size, padding, etc.) from the original field to the dummy. Since an element&amp;#8217;s scroll height is only available when it is visible on the page, the hidden element needs to be partially visible; the best way is to use the &lt;code&gt;visibility&lt;/code&gt; property:&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;
&lt;code class='javascript'&gt;element.style.visibility = &amp;amp;quot;hidden&amp;amp;quot;;
element.style.position = &amp;quot;absolute&amp;quot;;
element.style.height = &amp;quot;1px&amp;quot;;&lt;/code&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This ensures that the element will be rendered, but will not interfere with the rendering of the rest of the page.&lt;/p&gt;
&lt;p&gt;To magic a &lt;code&gt;textarea&lt;/code&gt;, simply invoke the script like so:&lt;/p&gt;
&lt;div&gt;
&lt;pre&gt;
&lt;code class='html'&gt;&amp;amp;lt;script&amp;amp;gt;
new DynamicTextAreaResizing(&amp;quot;my_text_area&amp;quot;);
&amp;lt;/script&amp;gt;&lt;/code&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;http://github.com/alexstaubo/form_utils/raw/5dc7212edc0eb0ab7e47b64b409e7692865e7799/dynamic_textareas.js&quot;&gt;&lt;/script&gt;&lt;p&gt;Here&amp;#8217;s a small demo. &lt;noscript&gt;(But you will need JavaScript turned out to try it out.)&lt;/noscript&gt;&lt;/p&gt;
&lt;textarea id=&quot;dynamically_resized_textarea&quot; cols=&quot;60&quot; rows=&quot;4&quot; class=&quot;big&quot;&gt;Type away, sir.&lt;/textarea&gt;
&lt;script&gt;new DynamicTextAreaResizing(&quot;dynamically_resized_textarea&quot;);&lt;/script&gt;&lt;p&gt;I have tested the code with Firefox 3, Safari 4, Internet Explorer 7 and Opera 9.6.&lt;/p&gt;
&lt;p&gt;A few notes on Firefox and Opera, though. Among all current browsers, Firefox is actually the least willing to make this technique work; Opera is better, but not by much. To start, Firefox does not wrap words that are wider than the field itself; Safari and IE both force a break, which is more convenient for the user than dealing with a horizontal scroll bar. (If you think this is rare, consider Flash or YouTube embeds, which often contain long links.)&lt;/p&gt;
&lt;p&gt;For this reason, the script does not set the field&amp;#8217;s &lt;code&gt;overflow&lt;/code&gt; style to &lt;code&gt;hidden&lt;/code&gt;, because doing so would prevent the horizontal scroll bar from showing in such cases. And for that reason, the resizing algorithm has to add a (fairly arbitrary) number of pixels to the height to accomodate the possibility of a horizontal scroll bar. Firefox is also considerably slower than the other browsers in rendering @textarea@s, which may be why it will briefly flash a vertical scroll bar just before the field is resized.&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;&lt;a href=&quot;http://github.com/alexstaubo/form_utils/raw/5dc7212edc0eb0ab7e47b64b409e7692865e7799/dynamic_textareas.js&quot;&gt;Download the script&lt;/a&gt; (&lt;span class=&quot;caps&quot;&gt;BSD&lt;/span&gt; license, currently requires &lt;a href=&quot;http://prototypejs.org/&quot;&gt;Prototype&lt;/a&gt;)&lt;/li&gt;
	&lt;li&gt;&lt;a href=&quot;http://github.com/alexstaubo/form_utils&quot;&gt;GitHub repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
    </entry>
   
</feed>

