JavaScript - - By Craig Buckler

How to Build an Auto-Expanding Textarea jQuery Plugin, Part 3

Auto-Expanding TextareaIn part 1 we discovered how an auto-expanding textarea could be built and collated the requirements. In part 2 we determined how coders would initialize our component. It’s now time to get our hands dirty with some JavaScript.

We are building a jQuery plugin named TextAreaExpander. You can read about the intricacies of jQuery plugin development in this tutorial, but the barebones of our code is:


(function($) {

	// jQuery plugin definition
	$.fn.TextAreaExpander = function(minHeight, maxHeight) {

		// ... our code ...

		return this;
	};

})(jQuery);

The $.fn statement then declares our new jQuery plugin, TextAreaExpander, with the arguments minHeight and maxHeight. We could express these in a JSON object but it’s unlikely we’ll need further parameters so we’ll keep it simple.

Note that ‘this’ refers to the jQuery object; we return it to ensure other jQuery effects can be bound to the same DOM elements.

Initializing the Textarea

The following initialization code is added to our TextAreaExpander function:


// initialize
this.each(function() {

	// is a textarea?
	if (this.nodeName.toLowerCase() != "textarea") return;

	// set height restrictions
	var p = this.className.match(/expand(d+)-*(d+)*/i);
	this.expandMin = minHeight || (p ? parseInt('0'+p[1], 10) : 0);
	this.expandMax = maxHeight || (p ? parseInt('0'+p[2], 10) : 99999);

	// initial resize
	ResizeTextarea(this);

	// add events
	if (!this.Initialized) {
		this.Initialized = true;
		$(this).css("padding-top", 0).css("padding-bottom", 0);
		$(this).bind("keyup", ResizeTextarea).bind("focus", ResizeTextarea);
	}
});

return this;
};

This loops through all the jQuery-selected DOM nodes and runs an anonymous function. The value of ‘this’ within that function is an individual textarea node. The following initialization occurs:

  1. The first line ensures that only textareas have the auto-expanding effect applied.
  2. The next three lines extract the minimum and maximum height values. The arguments passed to the TextAreaExpander function are used by default. If none are specified, the textarea’s “expand” class HTML is analysed with a regular expression. If we still do not have values, 0 and 99999 are assumed (note that the textarea will always have a minimum height of 1 character, so a zero height is never applied). The values are stored as properties of the textarea node object — we can therefore examine them from any code.
  3. The following line calls a ResizeTextarea function and passes the textarea node. This will set the height to an appropriate size when auto-expanding is initialized.
  4. Finally, we reset any vertical padding and define “keyup” and “focus” events. The same ResizeTextarea function is called when the textarea receives focus and after text has been updated by the user. The ‘if’ condition around these events ensures that they can only be applied once to any textarea. This condition could have been applied to the whole of the initialization function, however, this code allows us to change the minimum and maximum heights at will.

Resizing the Textarea

We now need to define our ResizeTextarea function.

In part 1, we discussed browser differences and noted that IE and Opera should never set a textarea height of 0px. Therefore, we will assign a variable that returns false if IE or Opera is being used:


var hCheck = !($.browser.msie || $.browser.opera);

It’s dirty, but I’m afraid that we cannot rely on better methods such as object detection. I’m open to suggestions, though!

We can now code our ResizeTextarea function:


// resize a textarea
function ResizeTextarea(e) {

	// event or element?
	e = e.target || e;

	// find content length and box width
	var vlen = e.value.length, ewidth = e.offsetWidth;
	if (vlen != e.valLength || ewidth != e.boxWidth) {

		if (hCheck && (vlen < e.valLength || ewidth != e.boxWidth)) e.style.height = "0px";
		var h = Math.max(e.expandMin, Math.min(e.scrollHeight, e.expandMax));

		e.style.overflow = (e.scrollHeight > h ? "auto" : "hidden");
		e.style.height = h + "px";

		e.valLength = vlen;
		e.boxWidth = ewidth;
	}

	return true;
};

This function is passed the argument ‘e’. This is either a textarea node (during initialization) or an event object (when keyup or focus occurs).

  1. The first line changes ‘e’ to a textarea node object if an event was fired.
  2. The number of characters entered in the textarea is assigned to vlen. The pixel-width of the box is assigned to ewidth. If these values have not changed, we do not need to worry about resizing the box (the user could just be moving the cursor). vlen and ewidth are retained as properties of the textarea node object named valLength and boxWidth. These are set after the textarea is resized so resizing will always occur the first time ResizeTextarea is called.
  3. The next line resets the textarea height to 0px. This only occurs for non-IE/Opera browsers if content has been deleted or the box width has been changed.
  4. The textarea’s scrollHeight value is now assigned to variable ‘h’. Math.min and Math.max are used to ensure the value falls within the minimum and maximum pixel limits defined for this textarea.
  5. Before we change the textarea height, we change the CSS overflow property. The scrollbars will only be shown if the content height exceeds the textarea height.
  6. We can now modify the textarea height and update the values of valLength and boxWidth.
  7. Finally, the function returns true to ensure other textarea event handlers are not cancelled.

Our TextAreaExpander jQuery plugin is complete. However, we need to ensure that the effect is applied to all textarea tags with an HTML “expand” class. At the end of our file, we can add an event which initializes all appropriate textareas after the page has loaded:


// initialize all expanding textareas
jQuery(document).ready(function() {
	jQuery("textarea[class*=expand]").TextAreaExpander();
});

I hope you’ve found this series of tutorials helpful. Feel free to use the auto-expanding textarea plugin in your own projects.

Useful resources:

See also: