Skip to content

Instantly share code, notes, and snippets.

@pamelafox
Created March 22, 2012 06:11
Show Gist options
  • Save pamelafox/2156602 to your computer and use it in GitHub Desktop.
Save pamelafox/2156602 to your computer and use it in GitHub Desktop.
TextArea AutoResizer (Bootstrap jQuery/Zepto Plugin)
var AutoResizer = function (textArea, options) {
var self = this;
this.$textArea = $(textArea);
this.minHeight = this.$textArea.height();
this.options = $.extend({}, $.fn.autoResizer.defaults, options)
this.$shadowArea = $('<div></div>').css({
position: 'absolute',
top: -10000,
left: -10000,
fontSize: this.$textArea.css('fontSize') || 'inherit',
fontFamily: this.$textArea.css('fontFamily') || 'inherit',
lineHeight: this.$textArea.css('lineHeight') || 'inherit',
resize: 'none'
}).appendTo(document.body);
var startWidth = this.$textArea.width() || $(window).width();
this.$shadowArea.width(startWidth);
if (this.options.resizeOnChange) {
function onChange() {
window.setTimeout(function() {
self.checkResize();
}, 0);
}
this.$textArea.change(onChange).keyup(onChange).keydown(onChange).focus(onChange);
}
this.checkResize();
};
AutoResizer.prototype = {
constructor: AutoResizer,
checkResize: function() {
// No sense in auto-growing non-visible textarea, which height of 0 implies
if (this.$textArea.height() === 0) {
return;
}
// If this is first time we've seen text area rendered, remember the height
if (this.minHeight === 0) {
this.minHeight = this.$textArea.height();
}
// If the text area has changed in size past a certain threshold of difference
// like when it becomes visible or viewport changes
if (this.$textArea.width() !== 0 && Math.abs(this.$shadowArea.width() - this.$textArea.width()) > 20) {
this.$shadowArea.width(this.$textArea.width());
}
var val = this.$textArea.val().replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/&/g, '&amp;')
.replace(/\n/g, '<br/>&nbsp;');
if ($.trim(val) === '') {
val = 'a';
}
this.$shadowArea.html(val);
var nextHeight = Math.max(this.$shadowArea[0].offsetHeight + 10, this.minHeight);
if (!this.prevHeight || nextHeight != this.prevHeight) {
this.$textArea.css('height', nextHeight);
this.prevHeight = nextHeight;
}
}
};
$.fn.autoResizer = function ( option ) {
return this.each(function () {
var $this = $(this)
, data = $this.data('autoresizer')
, options = typeof option == 'object' && option
if (!data) $this.data('autoresizer', (data = new AutoResizer(this, options)))
if (typeof option == 'string') data[option]()
else data.checkResize()
})
}
$.fn.autoResizer.defaults = {
resizeOnChange: true
};
$.fn.autoResizer.Constructor = AutoResizer;
@pamelafox
Copy link
Author

Right now the shadow doesn't mimic the padding of the text area, so I imagine the magic number has to do with that. It was good enough for me, but you should try displaying both shadow and text area at same time and you'll see how they differ (and then you can mirror a few more properties over).

@lerouxb
Copy link

lerouxb commented Mar 24, 2012

I happened to notice this commit via the whole svbtle/obtvse thing:
natew/obtvse@648e9a1

 textarea.onkeydown = function() {
    textarea.style.height = ""; /* Reset the height*/
    textarea.style.height = textarea.scrollHeight + "px";
};

Could it really be that simple?

@lerouxb
Copy link

lerouxb commented Mar 24, 2012

Here's a jsfiddle: http://jsfiddle.net/lerouxb/vRSP2/

Apart from being simpler it also has the benefit of not momentarily flashing a scrollbar. It isn't very smart about sizing back down again, though.

@rumpl
Copy link

rumpl commented Mar 24, 2012

There are some issues with backspace.

@rumpl
Copy link

rumpl commented Mar 24, 2012 via email

@rumpl
Copy link

rumpl commented Mar 24, 2012

Ok, sorry for the double post :)

@lerouxb
Copy link

lerouxb commented Mar 24, 2012

@xpachino
Copy link

xpachino commented Mar 4, 2015

Why dose the content jump as you continue to press enter? Tried it on facebook post comment textarea and it was seamless.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment