Sneaky Abstractions

Subscribe to my Feed, follow me on , recommend me on Working With Rails or see my code on GitHub

How to easily create an auto-expanding textarea

Posted on February 16, 2009 08:15 Tagged with javascript.

Just a quick tip on how to easily create textareas that automatically expand to fit their content. I’d always thought this was a rather complicated and obtrusive thing to do, but it turns out it’s not. The textarea tag has rows and columns attributes which are hints to the browser as to how big it should be. I, as many others I suspect, have always ignored these because I use CSS to control this and thought of them as remnants from an earlier age when CSS didn’t exist. But there’s really no conflict here; these attributes have semantic meaning, and the browser uses them only as a hint as to how to render the textarea. You can still set the max-height to prevent the textarea from growing too large, for example.

Thus, to create an auto-expanding textarea we just need to change the rows attribute (leaving columns out, because it’s not that useful and it’s more complicated, although possible) as the content changes. We could use the change event, but that only fires after the user leaves the textarea, which is not very useful. Instead, we need to observe the textarea to see if the content changes. “Observing” a textarea or any other DOM element is really just fancy talk for checking the contents every X milliseconds with setInterval:

//Prototype
(function(){ //Don't pollute the global scope

  var textarea = $('my_textarea');

  var oldValue = textarea.value;
  setInterval(function(){
    var newValue = textarea.value;
    if (newValue != oldValue) {//Value has changed
      //Set the "rows" attribute to the number of lines + 2
      textarea.writeAttribute('rows', newValue.split("\n").length+2);
      oldValue = newValue;
    }
  }, 500);//Check every 0.5s

})();

Now, whenever the content of the textarea changes, the rows attribute will be updated to the number of lines (plus two), and the browser will expand it.

But hang on, what it we’ve got 100 textareas on the page, won’t this mean we’ll have 100 interval functions running at the same time? Yes, it will, and that’s not really ideal. If you think about it, we only care about the content when the user is editing it, right? Knowing this, and that intervals can be removed, we can use the textarea’s focus and blur events to enable and disable the observer:

//Prototype
$$('.some_class_name').each(function(textarea){ //The 100 textareas

  var interval,
      oldValue = textarea.value,

      //The observer function is the same, only we're assigning
      //it to a variable to be re-used
      observer = function(){
        var newValue = textarea.value;
        if (newValue != oldValue) {//Value has changed
          //Set the "rows" attribute to the number of lines + 2
          textarea.writeAttribute('rows', newValue.split("\n").length+2);
          oldValue = newValue;
        }
      };

  //When the user focuses the textarea, create the observer interval
  textarea.observe('focus', function(){
    //Assign the interval to a variable so it can be removed later
    interval = setInterval(observer, 500);//Check every 0.5s
  });

  //When the user is finished editing, remove the interval
  textarea.observe('blur', function(){
    clearInterval(interval);
  });

});

Now, there will never be more than one interval running. Once the user moves focus away from the textarea, the interval is removed.

He who upholds Truth with all the might of his power
He who upholds Truth the utmost in his word and deed
He, indeed, is Thy most valued helper, O Mazda Ahura!