Automatic resizing of textarea in JavaScript and jQuery

It is very convenient when the text input field expands in height as text is entered. Modern browsers have the capability to resize the field. In this note, we will discuss how to make the textarea expand automatically when there is more text than it can accommodate.

Option 1: Textarea auto-resizing (using pure JavaScript)

Perhaps this is the best solution, so this is the first option.

The script can be found at this link: https://github.com/jackmoore/autosize

And here is the direct link to the JavaScript code that needs to be included in the HTML: https://github.com/jackmoore/autosize/blob/master/src/autosize.js

The installation is simple: you include the script file using wp_enqueue_script(). Then attach the resizing to the textarea element using one of the following options:

// list of elements
autosize( document.querySelectorAll('textarea') );

// single element
autosize( document.querySelector('textarea') );

// jQuery elements
autosize( $('textarea') );

Browser support:

Chrome Firefox IE Safari iOS Safari Android Opera Mini
yes yes 9 yes yes 4 ?

Option 2: Textarea auto-resizing (jQuery plugin)

If you have the jQuery library installed on your site, then I recommend a good plugin for the automatic resizing of textarea, which can be found here: https://amaury.carrade.eu/projects/jquery/autoResize.html

Here is the minified version of the plugin code:

/*
 * jQuery autoResize (textarea auto-resizer)
 * @copyright James Padolsey http://james.padolsey.com
 * @version 1.04.1 (kama fix)
 */
(function(b){b.fn.autoResize=function(f){var a=b.extend({onResize:function(){},animate:!0,animateDuration:150,animateCallback:function(){},extraSpace:20,limit:1E3},f);this.filter("textarea").each(function(){var d=b(this).css({"overflow-y":"hidden",display:"block"}),f=d.height(),g=function(){var c={};b.each(["height","width","lineHeight","textDecoration","letterSpacing"],function(b,a){c[a]=d.css(a)});return d.clone().removeAttr("id").removeAttr("name").css({position:"absolute",top:0,left:-9999}).css(c).attr("tabIndex","-1").insertBefore(d)}(),h=null,e=function(){g.height(0).val(b(this).val()).scrollTop(1E4);var c=Math.max(g.scrollTop(),f)+a.extraSpace,e=b(this).add(g);h!==c&&(h=c,c>=a.limit?b(this).css("overflow-y",""):(a.onResize.call(this),a.animate&&"block"===d.css("display")?e.stop().animate({height:c},a.animateDuration,a.animateCallback):e.height(c)))};d.unbind(".dynSiz").bind("keyup.dynSiz",e).bind("keydown.dynSiz",e).bind("change.dynSiz",e)});return this}})(jQuery);

// initialization
jQuery(function(){
	jQuery('textarea').autoResize();
});

Once this code is installed, all textareas should automatically resize.

Browser support:

  • IE 6-8
  • Firefox 3.5
  • Opera 9.5-10
  • Safari 3
  • Chrome 10

During testing, it was found that the textarea must have the css property display:block set, otherwise no animations in the plugin worked (Chrome browser). Therefore, a few lines of code were added to the plugin to set this property automatically. Also, in some browsers, there is the possibility to manually change the size of the textarea (using the triangle in the corner), the plugin inexplicably removed this feature, so it was restored. Hence the version header @version 1.04.1 (kama fix)

Uncompressed version of the plugin code:
/*
 * jQuery autoResize (textarea auto-resizer)
 * @copyright James Padolsey http://james.padolsey.com
 * @version 1.04.1 (kama fix)
 */
(function($){

	$.fn.autoResize = function(options) {

		// Just some abstracted details,
		// to make plugin users happy:
		var settings = $.extend({
			onResize : function(){

			},
			animate : true,
			animateDuration : 150,
			animateCallback : function(){},
			extraSpace : 20,
			limit: 1000
		}, options);

		// Only textarea's auto-resize:
		this.filter('textarea').each(function(){

				// Get rid of scrollbars and disable WebKit resizing:
			var textarea = $(this).css({'overflow-y':'hidden', display:'block'}),

				// Cache original height, for use later:
				origHeight = textarea.height(),

				// Need clone of textarea, hidden off screen:
				clone = (function(){

					// Properties which may effect space taken up by chracters:
					var props = ['height','width','lineHeight','textDecoration','letterSpacing'],
						propOb = {};

					// Create object of styles to apply:
					$.each(props, function(i, prop){
						propOb[prop] = textarea.css(prop);
					});

					// Clone the actual textarea removing unique properties
					// and insert before original textarea:
					return textarea.clone().removeAttr('id').removeAttr('name').css({
						position: 'absolute',
						top: 0,
						left: -9999
					}).css(propOb).attr('tabIndex','-1').insertBefore(textarea);

				})(),
				lastScrollTop = null,
				updateSize = function() {
					// Prepare the clone:
					clone.height(0).val($(this).val()).scrollTop(10000);

					// Find the height of text:
					var scrollTop = Math.max(clone.scrollTop(), origHeight) + settings.extraSpace,
						toChange = $(this).add(clone);

					// Don't do anything if scrollTip hasen't changed:
					if (lastScrollTop === scrollTop) { return; }
					lastScrollTop = scrollTop;

					// Check for limit:
					if ( scrollTop >= settings.limit ) {
						$(this).css('overflow-y','');
						return;
					}
					// Fire off callback:
					settings.onResize.call(this);

					// Either animate or directly apply height:
				   settings.animate && textarea.css('display') === 'block' ?
						toChange.stop().animate({height:scrollTop}, settings.animateDuration, settings.animateCallback)
						: toChange.height(scrollTop);

				};

			// Bind namespaced handlers to appropriate events:
			textarea
				.unbind('.dynSiz')
				.bind('keyup.dynSiz', updateSize)
				.bind('keydown.dynSiz', updateSize)
				.bind('change.dynSiz', updateSize);

		});

		// Chain:
		return this;

	};

})(jQuery);

Plugin customization

During the initialization of the plugin, certain parameters can be set.

1. Remove the bottom margin, by default, it is 20 pixels:
jQuery('textarea').autoResize({
	 extraSpace : 0
});
2. Attach actions during and after resizing - settings for onResize and animateCallback:
jQuery('textarea').autoResize({
	// During resizing:
	onResize : function() {
		jQuery(this).css({ color:'#666', background:'#eee' });
	},
	// After resizing:
	animateCallback : function() {
		jQuery(this).css({ color:'#222', background:'#fff' });
	}
});

All settings

onResize(function)
A function called during the textarea resizing. Passes the textarea object, i.e., "this" will be the working textarea in the function.
animate(boolean)
Whether animation of height changes is enabled. true - enabled.
Default: true
animateDuration(number)
The duration of the animation in milliseconds.
Default: 150
animateCallback(function)
Called at the end of the animation.
extraSpace(number)
Bottom margin for the textarea in pixels.
Default: 20
limit(number)
Maximum height of the textarea in pixels. Scroll will appear above this limit.
Default: 1000

Variant 3: auto-stretching textarea (my old script)

It turned out that the first version of the script for automatically stretching the comment field in WordPress was not the best smile. When I was testing it, I didn't notice a bug, which caused the screen to jump up when the field was stretched significantly, making it impossible to leave a large comment shock. Additionally, the script was lagging in IE 8.

After spending many hours trying to fix the script, I realized that it was impossible - something needed to be fundamentally changed. As a result, I started looking for an alternative solution. I came across solutions based on jQuery, but I wanted to do this with pure JS. I kept the jQuery solution as a last resort.

While browsing, I found a solution that seemed acceptable to me in terms of convenience. You can view this solution in this demo (it might be useful to someone). After tweaking the script a bit, I realized that achieving a simple integration into WordPress was not possible (it required adding to the comment form, adding CSS, and of course connecting the script), but I wanted it to be easy: insert the script and it's ready. After all, such questionable usability isn't worth the extra effort.

So I continued to search and found an interesting function for counting lines, which I then completed. The result satisfied me: take a look at this DEMO version.

Advantages of this variant of resizing the comment field:

  • Simple integration into the template;
  • Good height calculation;
  • No lag.

This is a new option, as of December 16, 2013. I adjusted the code, fixed a bug - the code was written a bit incorrectly and could burden the computer. This is no longer the case.

/**
 * Script for automatically stretching the textarea vertically.
 *
 * For the script to work, the height of the textarea should not be strictly defined, i.e.
 * the CSS property height should NOT be defined. Instead of height, you can use
 * min-height:200px; or it's better to set the height using rows=''.
 * You can also limit the maximum stretching height
 * through the CSS property max-height:800px;
 *
 * Author: Timur Kamaev - http://wp-kama.ru
 * Version 4.0
*/

// settings
var krVar = {
	// id attribute of the textarea tag
	textareaId: 'comment',
	// recalculation time (1000=1sec).
	repeat: 1000,
	// coefficient. Increase if there is scrolling.
	cof: 40,

}

var KR = {
	timeout:0,
	textarea: document.getElementById( krVar.textareaId ),

	init: function(){
		if( ! KR.textarea )
			return;

		KR.textarea.onfocus = KR.doit;
		KR.textarea.onblur = KR.stop;
	},
	doit: function(){
		// set the necessary number of rows
		KR.textarea.rows = KR.countLines( KR.textarea.value );

		clearTimeout( KR.timeout );
		KR.timeout = setTimeout( function(){ KR.doit(); }, krVar.repeat );
	},
	stop: function(){
		clearTimeout( KR.timeout );
	},
	// function for counting lines
	countLines: function( strtocount ){
		var hard_lines = 0;
		var str = strtocount.split("\n");
		hard_lines = str.length;

		var tx = KR.textarea;
		var letter_width = tx.clientHeight / tx.rows * krVar.cof / 100; // approximate width of one letter in pixels
		var chars_in_line = tx.clientWidth / letter_width; // how many letters in a line

		var lines = 0;
		var temp = 0;

		// hard_lines-1 = number of elements in the array
		for( i=0; i <= (hard_lines-1); i++ ){
			temp = str[i].length / chars_in_line;
			if( temp > 0 ) lines += temp;
		}

		return lines + hard_lines;
	}
}

window.addEventListener( "load", KR.init, false );

Script installation

  1. Copy the code above into any existing javascript file in the template;

  2. Set the textarea CSS property min-height (see below for how to do this);

  3. (optional) If you don't want the field to stretch infinitely, set the CSS property max-height;

How to insert the script directly into the theme file:

If you don't have a js file in your template, you can create one, copy the code there, and then connect the file to the template.

Or you can simply include the above-written code in your template file single.php by inserting such a construction in the file:

<script type="text/javascript">/* <![CDATA[ */

Here goes the code

/* ]]> */</script>

How to set the textarea CSS property min-height

Option 1: Open the comments.php file, find the HTML textarea tag, and add style='min-height:200px; max-height:700px;' to it. It will look something like this:

<textarea style="min-height:200px; max-height:700px;" rows="58" name="comment" id="comment" tabindex="4"></textarea>

You can omit max-height:700px; - this is the maximum length to which the field will stretch.

Option 2: Find the class responsible for the textarea field in your style file (style.css) and add the CSS property min-height:200px; to it. If it has the property height:XXXpx, it should be removed.

Several possible class names for the field:

#commentform textarea{}

#respond textarea{}

#comment{}
textarea#comment{}

Technical details: how the script works

The code works as follows: when the cursor enters the comment field, periodic line counting is initiated (every half second), and when the cursor leaves the field, the line counting stops. The lines are counted by summing the number of explicit line breaks (\n) and calculating implicit line breaks (when a line wraps to a new line due to insufficient width of the field, which required a lot of effort to achieve).

The main difference from the previous version is that another technology is used to count the lines, and the lines are not counted with every keystroke but after a certain time, in our case 500 milliseconds (half a second). The interval can be increased if there are delays. In solutions where the height calculation is triggered by a keystroke, there are always delays, especially on slow computers and with fast typing.

If you have any questions, feel free to ask in the comments!