Is there a jQuery autogrow plugin for text fields?

Solution 1:

Here's a plugin that'll do what you're after:

EDIT: I've fixed the plugin as per Mathias' comment. :)

See a demo here: http://jsfiddle.net/rRHzY

The plugin:

(function($){

    $.fn.autoGrowInput = function(o) {

        o = $.extend({
            maxWidth: 1000,
            minWidth: 0,
            comfortZone: 70
        }, o);

        this.filter('input:text').each(function(){

            var minWidth = o.minWidth || $(this).width(),
                val = '',
                input = $(this),
                testSubject = $('<tester/>').css({
                    position: 'absolute',
                    top: -9999,
                    left: -9999,
                    width: 'auto',
                    fontSize: input.css('fontSize'),
                    fontFamily: input.css('fontFamily'),
                    fontWeight: input.css('fontWeight'),
                    letterSpacing: input.css('letterSpacing'),
                    whiteSpace: 'nowrap'
                }),
                check = function() {

                    if (val === (val = input.val())) {return;}

                    // Enter new content into testSubject
                    var escaped = val.replace(/&/g, '&amp;').replace(/\s/g,'&nbsp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
                    testSubject.html(escaped);

                    // Calculate new width + whether to change
                    var testerWidth = testSubject.width(),
                        newWidth = (testerWidth + o.comfortZone) >= minWidth ? testerWidth + o.comfortZone : minWidth,
                        currentWidth = input.width(),
                        isValidWidthChange = (newWidth < currentWidth && newWidth >= minWidth)
                                             || (newWidth > minWidth && newWidth < o.maxWidth);

                    // Animate width
                    if (isValidWidthChange) {
                        input.width(newWidth);
                    }

                };

            testSubject.insertAfter(input);

            $(this).bind('keyup keydown blur update', check);

        });

        return this;

    };

})(jQuery);

Solution 2:

I have a jQuery plugin on GitHub: https://github.com/MartinF/jQuery.Autosize.Input

It uses the same approach as James answer but have some of the changes mentioned in the comments.

You can see an live example here: http://jsfiddle.net/mJMpw/6/

Example:

<input type="text" value="" placeholder="Autosize" data-autosize-input='{ "space": 40 }' />

input[type="data-autosize-input"] {
  width: 90px;
  min-width: 90px;
  max-width: 300px;
  transition: width 0.25s;    
}

You just use css to set min/max-width and use a transition on the width if you want a nice effect.

You can specify the space / distance to the end as the value in json notation for the data-autosize-input attribute on the input element.

Of course you can also just initialize it using jQuery

$("selector").autosizeInput();

Solution 3:

Good plugin, thank you! I changed two things that seemed to work better in my project though.

  1. I changed the TESTER tag to a DIV, to avoid getting 'Unexpected call to method or property access.' in IE8 (even though your demo does work in IE8. Was there a particular reason for for using a custom HTML tag?
  2. After the bind statement near the end of the code, I added a call to check(), in order to resize the textbox immediately after loading the page, in case the textbox already has content in it on startup.

Hope this helps.

Solution 4:

just wanted to share a small improvement to James's great plugin. Add this code to the CSS declaration for the tester element to account for text-indent:

textIndent: 0

Without it, in some situations the tester element may inadvertently inherit the text-indent from elsewhere, thus throwing off the size of the input.

Like JP, I also wanted to resize the input to the correct size from the beginning, which I did just slightly differently, by chaining "trigger('keyup')" to the autoGrowInput method call, e.g.:

$('#contact_form').autoGrowInput({comfortZone: 7, minWidth: 10, maxWidth: 200}).trigger('keyup');

As a side note, I signed up to this site purely to comment on James's solution and I'm a bit annoyed to find that I can't because I don't have enough reputation points to start with. Sorry if I've missed something, but that seems to mean that I have to post this is a comment on the main question rather than more appropriately on James's solution.