Creating a textarea with auto-resize
Asked Answered
T

52

534

There was another thread about this, which I've tried. But there is one problem: the textarea doesn't shrink if you delete the content. I can't find any way to shrink it to the correct size - the clientHeight value comes back as the full size of the textarea, not its contents.

The code from that page is below:

function FitToContent(id, maxHeight)
{
   var text = id && id.style ? id : document.getElementById(id);
   if ( !text )
      return;

   var adjustedHeight = text.clientHeight;
   if ( !maxHeight || maxHeight > adjustedHeight )
   {
      adjustedHeight = Math.max(text.scrollHeight, adjustedHeight);
      if ( maxHeight )
         adjustedHeight = Math.min(maxHeight, adjustedHeight);
      if ( adjustedHeight > text.clientHeight )
         text.style.height = adjustedHeight + "px";
   }
}

window.onload = function() {
    document.getElementById("ta").onkeyup = function() {
      FitToContent( this, 500 )
    };
}
Tithonus answered 17/1, 2009 at 22:30 Comment(4)
possible duplicate of Autosizing textarea using prototypeWimsatt
I created a package for this if you are using react: npmjs.com/package/react-fluid-textareaSenegambia
Sort and Sweet answer here : https://mcmap.net/q/74843/-textarea-to-resize-based-on-content-length-duplicate function textAreaAdjust(o) { o.style.height = "1px"; o.style.height = (25+o.scrollHeight)+"px"; } <textarea onkeyup="textAreaAdjust(this)" style="overflow:hidden"></textarea> Lice
Using CSS (and a wrapper element) only: css-tricks.com/the-cleanest-trick-for-autogrowing-textareasAfterdamp
F
276

This works for me (Firefox 3.6/4.0 and Chrome 10/11):

var observe;
if (window.attachEvent) {
    observe = function (element, event, handler) {
        element.attachEvent('on'+event, handler);
    };
}
else {
    observe = function (element, event, handler) {
        element.addEventListener(event, handler, false);
    };
}
function init () {
    var text = document.getElementById('text');
    function resize () {
        text.style.height = 'auto';
        text.style.height = text.scrollHeight+'px';
    }
    /* 0-timeout to get the already changed text */
    function delayedResize () {
        window.setTimeout(resize, 0);
    }
    observe(text, 'change',  resize);
    observe(text, 'cut',     delayedResize);
    observe(text, 'paste',   delayedResize);
    observe(text, 'drop',    delayedResize);
    observe(text, 'keydown', delayedResize);

    text.focus();
    text.select();
    resize();
}
textarea {
    border: 0 none white;
    overflow: hidden;
    padding: 0;
    outline: none;
    background-color: #D0D0D0;
}
<body onload="init();">
<textarea rows="1" style="height:1em;" id="text"></textarea>
</body>

If you want try it on jsfiddle It starts with a single line and grows only the exact amount necessary. It is ok for a single textarea, but I wanted to write something where I would have many many many such textareas (about as much as one would normally have lines in a large text document). In that case it is really slow. (In Firefox it's insanely slow.) So I really would like an approach that uses pure CSS. This would be possible with contenteditable, but I want it to be plaintext-only.

Floorage answered 18/3, 2011 at 0:21 Comment(16)
This unfortunately fails in IE8, and since it uses overflow: hidden it leaves IE users with no fallback plan. You could toggle overflow on and off to resolve that, but then the scrollbar loses its mind. If you don't use overflow: hidden the textarea doesn't shrink. Close though!Lozada
Using IE tester the code above even works with IE 5.5. I didn't test with IE 9 because I only have XP installed in my VirtualBox.Floorage
It does! Made a jsfiddle for ya: jsfiddle.net/CbqFv It now works in Chrome, Firefox, and IE8 - although it is a little glitchy in IE8. As you increase or decrease number of lines it freaks out a little. As you might have seen in the autoresize plugin for jQuery, they work around that by cloning the textarea, setting its height to auto instead of the original, then using that to set scrollheight on the original. I did that in this updated fiddle: jsfiddle.net/CbqFv/2 It solves the IE issue but Firefox stops working.Lozada
Thanks, but I see it's using an id='text' to search for the DOM. But I can't use the same Id for more than one textarea, so how do I change it to a class that can be used by others? Thanks again.Veilleux
@HelenNeely: Then don't use an id. E.g. use a class and do what init does for all elements of that class. That should be a beginners task.Floorage
If you want to target modern browsers, you don't need to attach the handler to all those events. Just attach to input or oninput event.Aurilia
@DenilsonSá If one could only assume that only modern browsers are used the web would be a better place.Floorage
Does this work if I have multiple textboxes that require the feature?Springe
This won't work well if a scrollbar is envolved in IE11. If you use this fiddle jsfiddle.net/CbqFv and enter lines until you've got a scrollbar you will see it. Any ideas?Ptolemy
kaljak, does adding overflow: hidden; help? Edit: Wait, that is already there. Then no idea.Floorage
What can I do for prevent scroll bar flashing? If the style overflow:auto;Mini
@Mini Maybe use an visibility:hidden;position:fixed; textarea/div to measure the height? Or use a contentEditable="true"-div instead of a textarea (which complicates other things heavily).Floorage
This breaks completely if the textarea is near the bottom page end - everything jumps back and forward due to style.height='auto'. I suspect the solution is to add a hidden sibling used only for measurement.Bevash
would it hang the browser if pasted large text inside like 3MB file after uploading and getting the response back into the textareaSpoilt
On Firefox 70 it doesn't resize on first character that overflows. On second char it gets resized.Goines
This works fine on JSFuddle, but I'm wondering (as I have such task to do) how it does behave if you increasing and decreasing the font size from the browser settings. Also across different languages?Crespo
J
661

A COMPLETE YET SIMPLE SOLUTION

Updated 2023-06-08 (Added native js for updating via js injection)

The following code will work:

  • On key input.
  • With pasted text (right click & ctrl+v).
  • With cut text (right click & ctrl+x).
  • With pre-loaded text.
  • With all textareas (multiline textboxes) site wide.
  • With Firefox (v31-109 tested).
  • With Chrome (v37-108 tested).
  • With IE (v9-v11 tested).
  • With Edge (v14-v108 tested).
  • With IOS Safari.
  • With Android Browser.
  • With JavaScript strict mode.

OPTION 1 (With jQuery)

This option requires jQuery and has been tested and is working with 1.7.2 - 3.6.3

Simple (Add this jQuery code to your master script file and forget about it.)

$("textarea").each(function () {
  this.setAttribute("style", "height:" + (this.scrollHeight) + "px;overflow-y:hidden;");
}).on("input", function () {
  this.style.height = 0;
  this.style.height = (this.scrollHeight) + "px";
});
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-3.6.3.min.js"></script>
<textarea placeholder="Type, paste, cut text here...">PRELOADED TEXT.
This JavaScript should now add better support for IOS browsers and Android browsers.</textarea>
<textarea placeholder="Type, paste, cut text here..."></textarea>

Test on jsfiddle


OPTION 2 (Pure JavaScript)

Simple (Add this JavaScript to your master script file and forget about it.)

const tx = document.getElementsByTagName("textarea");
for (let i = 0; i < tx.length; i++) {
  tx[i].setAttribute("style", "height:" + (tx[i].scrollHeight) + "px;overflow-y:hidden;");
  tx[i].addEventListener("input", OnInput, false);
}

function OnInput() {
  this.style.height = 'auto';
  this.style.height = (this.scrollHeight) + "px";
}
<textarea placeholder="Type, paste, cut text here...">PRELOADED TEXT. This JavaScript should now add better support for IOS browsers and Android browsers.</textarea>
<textarea placeholder="Type, paste, cut text here..."></textarea>

Test on jsfiddle


OPTION 3 (jQuery Extension)

Useful if you want to apply further chaining to the textareas, you want to be auto-sized.

jQuery.fn.extend({
  autoHeight: function () {
    function autoHeight_(element) {
      return jQuery(element)
        .css({ "height": 0, "overflow-y": "hidden" })
        .height(element.scrollHeight);
    }
    return this.each(function() {
      autoHeight_(this).on("input", function() {
        autoHeight_(this);
      });
    });
  }
});

Invoke with $("textarea").autoHeight()


UPDATING TEXTAREA VIA JAVASCRIPT

When injecting content into a textarea via JavaScript, append the following line of code to invoke the resize function.

jQuery

$("textarea").trigger("input");

Pure JavaScript

document.getElementsByTagName("textarea")[0].dispatchEvent(new Event('input', { bubbles: true }));

PRESET TEXTAREA HEIGHT

To fix the initial height of the textarea you will need to add another condition:

const txHeight = 16;
const tx = document.getElementsByTagName("textarea");

for (let i = 0; i < tx.length; i++) {
  if (tx[i].value == '') {
    tx[i].setAttribute("style", "height:" + txHeight + "px;overflow-y:hidden;");
  } else {
    tx[i].setAttribute("style", "height:" + (tx[i].scrollHeight) + "px;overflow-y:hidden;");
  }
  tx[i].addEventListener("input", OnInput, false);
}

function OnInput(e) {
  this.style.height = 'auto';
  this.style.height = (this.scrollHeight) + "px";
}
<textarea placeholder="Type, paste, cut text here...">PRELOADED TEXT. This JavaScript should now add better support for IOS browsers and Android browsers.</textarea>
<textarea placeholder="Type, paste, cut text here..."></textarea>
Jayson answered 2/9, 2014 at 10:31 Comment(49)
This is a great solution, it would be slightly more understandable if the method name and parameter name were updated to be true names instead of individual letters.Erasmoerasmus
It's quite strange that when I use $("#xxx").val("xxx").trigger("input"), it does trigger the input event, however the .scrollHeight attribute still returns 0. I don't understand. lolSeline
@Seline I can't say I noticed that before. Does this impact on what you are trying to achieve? Are you reading the value after the trigger event has completed? You could use a callback function at the end of the function.Jayson
@Obsidian I had to use Math.max(40, e.scrollHeight) to avoid a 0 height. As for the callback, could you give me more details? I have no idea how to apply a callback here.Seline
@Seline I updated the fiddle to test for scrolleight. If checked during the callback of the input the scroll height reads correctly. See the alert here on input. jsfiddle.net/n9uuv0hd/8Jayson
@Obsidian Thanks! I just figured out why I always get a 0 —— I put the textarea in a Bootstrap modal! As the modal is hidden at first, textarea in it will have a 0 scrollHeight 😂😂Seline
@Obsidian Fantastic!! (Option 3). The this.style.height = 'auto'; is the magic behavior fix. I was so frustrated why the scrollHeight was so weird in behavior. The height to auto, then matching the scrollHeight in the same render cycle still blows my mind how it 'fixes' this issue though it should only be technically painting the second height.Yeeyegg
I tried option 3 in Chrome today and had to make a couple tweaks. 1) It won't always resize down correctly if you have a "height" or "all" transition on the textarea. I'd recommend not using transitions that affect height. 2) The scrollHeight was returning a minumum of two rows worth of height (perhaps because that's the default for textareas in Chrome) but if you change this.style.height = 'auto'; to this.style.height = '0px'; and add a min-height to prevent the initial state from actually going to 0, scrollHeight will correctly return one row of height when appropriate.Thirteenth
@Obsidian Can you explain how this.style.height = 'auto'; fixes the behaviour of scrollHeight? It's just magic.Meaningful
@Meaningful Simply: Using auto first simply allows the height of the textarea to be reset to the correct height of its content before the changes are made using scrollheight.Jayson
Few things: I use the first option in a modal. On mobile, it changes scroll in weird way when typing, which is annoying. Second: Page up/down buttons do not work with this script.Diplomacy
@Soaku Please can you provide an example as I have no issue with either of the points you mention but I want the script to be as effective as possible so if there are issues I would like to fix them.Jayson
@Obsidian Have you tried using the textara with text spanning more than 100% screen height? Then the first glitch occurs,Diplomacy
@Soaku yes, jsfiddle.net/n9uuv0hd/94 works fine in chrome and operates as textarea home end in firefox. Can you create a fiddle with your problem?Jayson
@Obsidian Actually, the bug is present in your fiddle. When I type, the scroll is "teleported", so the pointer is right in top of the keyboard, when I press "enter", it returns to previous position.Diplomacy
@Obsidian Unfortunately it seems like because of this.style.height = 'auto'; CSS transitions on height don't work. I can either have transitions working and resizing on deleting lines broken or transitions not working and resizing on deleting lines working. Any workarounds?Meaningful
@Meaningful Yes it is a difficulty I have yet to overcome. Although I found that transitioning the height, although looked good was not well received by my customer base. In this case speed over style was better!Jayson
elem[0].scrollHeight may help for the case elem.scrollHeight does not workKwangju
Why is mine not working? Does it work in react too? I include the main.js file in the index.html but it doesn't work somehow. It looks like the function is not being calledDanita
@KittichoteKamalapirat if you create a new question showing an example of your current code, I would be happy to try and help you with it. For now I would make sure jQuery is initialised before your main.js file. I would then verify that your entire main.js file has no errors because a single missed semi-colon would cascade failure through your document.Jayson
@Jayson Thanks for the response. I have added the question here, please check it out. Let me know if the info I provided was not enough #58008893Danita
For some reason my textarea stays at 0px on pageload even with preloaded text. I can see that it works in the jsfiddle example (Option 1) but I have the exact same code in my app and it don't work. :-( It works when I type in the textarea but it doesn't work on page load.Aintab
@Aintab Then you must have other conflicting code in your app. This is likely css or Javascript. Try using the browsers web console while running your app to see what is applying the height to the textarea.Jayson
There still is a use case not answered by your example: if the initial textarea height is not the auto one? An empty textarea is two rows height. If I take the jsfiddle of your second example and add an initial style="height: 33px" to the empty textarea, you'll see that your code breaks the height of the textarea, making it two rows again...Bothy
@fla The code doesn't break it does what it's been programmed to do. Setting an inline style height will be ignored by the script due to specificity. If you wanted a default height for the empty field then you would need to add a caveat in the javascript function to check for empty content and then set the inital height differantly. e.g jsfiddle.net/fxre1zm5Jayson
It's not about empty content, it's about one line only textarea. The textarea height is supposed to be the content height. If my content is on one line only, the textarea height should be one line, not two.Bothy
@fla An input with type="textarea" is multiline by default however you can change the deaault behaviour using my suggestion. Did this not work for you?Jayson
if anyone has trouble with initial height of textarea just get and set height ONLY after setting overflow hidden $el.style['overflow-y'] = 'hidden'; $el.style.height = $el.scrollHeight + 'px';Incision
I used the "pure javascript" one. It works really well, and definitely helped me. Thanks! Funnily enough I couldn't get the other answer's version to work, so I'm quite glad you added this.Atop
The height with one line of text can be reduced to a single line by setting rows="1". Also, watch out for any answer (including this one) that directly manipulates the height of the textarea to calculate the final height: current versions of iOS Safari have a bug in which scrolling will jump up and down erratically as you enter newlines in a tall textarea as it attempts to keep the textarea in the view. You can use an invisible, second textarea for the calculations to fix this. Also consider that width changes, caused by page size changes, etc, may affect the ideal height.Ragsdale
To avoid the scroll position changing when the textarea height was more than 100% of the window height, I store the pageYOffset at the start of OnInput and then if the pageYOffset is greater after setting the height, then I reset it to the starting pageYOffset. Works a treat. jsfiddle.net/L8259hodAirspeed
At least in current Firefox (93), this is really slow because it reads and changes each one, and that forces a reflow for the page. In a related post which I can't find now, someone pointed out that what you want to do is read ALL the scrollHeight values, and then set ALL the style attributes without reading anything. In current Firefox, this strategy is waaaaay faster.Lichi
@SamBayer by "really slow" what are you talking about (milliseconds?) because I use this on Firefox everyday on all my applications and the thought it was slow never occurred to me.Jayson
I have used solution two and it works except when moving between tabs created. I don't know why textareas that are not visible directly on the page is not autosized until I type in them. Does this method not work on textareas not visible from page load?Isfahan
@Isfahan A textarea that is invisble on the page has an initial height of 0. When your tab changes to it the textarea will become visible but the height is still 0. To fix this you need to trigger the routine on tab change. (See UPDATING TEXTAREA VIA JAVASCRIPT part of answer)Jayson
@Jayson I tried that now and it didn't work. I see there is a way to preset the height of the boxes but is there a way to preset it to auto height? Can I modify the "PRESET TEXTAREA HEIGHT" to work with auto height?Isfahan
@Isfahan The code will work, I came accross the same issue myself previsouly. Create a separate question with your code in and I will see if I can assist.Jayson
Created a qustion: #71207189 @Jayson Thanks for taking your so far time.Isfahan
Instead of using "auto" for the initial height, you can also use 0.Tiflis
@Thirteenth 's suggestion should be incorporated into the answer. Without it, the solution is essentially broken for line sizes of 1.Cardsharp
@Cardsharp Doesn't the PRESET TEXTAREA HEIGHT option accomodate for this requirement?Jayson
No, the PRESET TEXTAREA HEIGHT is about setting the initial height of the element. ZorroDeLaArena's suggestion #2 is about height: auto giving the textarea 2 lines when only 1 is needed (at least in Chrome). He suggested using 0 for the height rather than auto, and setting a min-height on the element. I just used 1rem for the height and didn't need a min-height. In short: change "auto" to "0" or "1rem" and the code works better in the case where only one line is needed in the textarea.Cardsharp
@Cardsharp OK thanks. I have tested the findings and ammended the answer to accomodate.Jayson
@DreamTeK, can you help me with this question, I try to convert your answer to ReactJS #73917449Pule
You capture onInput here, but not the form's onReset event. So textareas won't resize if you reset the form they're in!Zipper
I would also change the .on("input") to .on("focus") so that it resizes as soon as you put your cursor in the input.Aintab
@Vincent, but the size won't change until the content is edited.Jayson
you should stop resizing the box if the user manually resizes itViscosity
@BorisVerkhovskiy that's a good idea, but I think it would need to be optional.Jayson
F
276

This works for me (Firefox 3.6/4.0 and Chrome 10/11):

var observe;
if (window.attachEvent) {
    observe = function (element, event, handler) {
        element.attachEvent('on'+event, handler);
    };
}
else {
    observe = function (element, event, handler) {
        element.addEventListener(event, handler, false);
    };
}
function init () {
    var text = document.getElementById('text');
    function resize () {
        text.style.height = 'auto';
        text.style.height = text.scrollHeight+'px';
    }
    /* 0-timeout to get the already changed text */
    function delayedResize () {
        window.setTimeout(resize, 0);
    }
    observe(text, 'change',  resize);
    observe(text, 'cut',     delayedResize);
    observe(text, 'paste',   delayedResize);
    observe(text, 'drop',    delayedResize);
    observe(text, 'keydown', delayedResize);

    text.focus();
    text.select();
    resize();
}
textarea {
    border: 0 none white;
    overflow: hidden;
    padding: 0;
    outline: none;
    background-color: #D0D0D0;
}
<body onload="init();">
<textarea rows="1" style="height:1em;" id="text"></textarea>
</body>

If you want try it on jsfiddle It starts with a single line and grows only the exact amount necessary. It is ok for a single textarea, but I wanted to write something where I would have many many many such textareas (about as much as one would normally have lines in a large text document). In that case it is really slow. (In Firefox it's insanely slow.) So I really would like an approach that uses pure CSS. This would be possible with contenteditable, but I want it to be plaintext-only.

Floorage answered 18/3, 2011 at 0:21 Comment(16)
This unfortunately fails in IE8, and since it uses overflow: hidden it leaves IE users with no fallback plan. You could toggle overflow on and off to resolve that, but then the scrollbar loses its mind. If you don't use overflow: hidden the textarea doesn't shrink. Close though!Lozada
Using IE tester the code above even works with IE 5.5. I didn't test with IE 9 because I only have XP installed in my VirtualBox.Floorage
It does! Made a jsfiddle for ya: jsfiddle.net/CbqFv It now works in Chrome, Firefox, and IE8 - although it is a little glitchy in IE8. As you increase or decrease number of lines it freaks out a little. As you might have seen in the autoresize plugin for jQuery, they work around that by cloning the textarea, setting its height to auto instead of the original, then using that to set scrollheight on the original. I did that in this updated fiddle: jsfiddle.net/CbqFv/2 It solves the IE issue but Firefox stops working.Lozada
Thanks, but I see it's using an id='text' to search for the DOM. But I can't use the same Id for more than one textarea, so how do I change it to a class that can be used by others? Thanks again.Veilleux
@HelenNeely: Then don't use an id. E.g. use a class and do what init does for all elements of that class. That should be a beginners task.Floorage
If you want to target modern browsers, you don't need to attach the handler to all those events. Just attach to input or oninput event.Aurilia
@DenilsonSá If one could only assume that only modern browsers are used the web would be a better place.Floorage
Does this work if I have multiple textboxes that require the feature?Springe
This won't work well if a scrollbar is envolved in IE11. If you use this fiddle jsfiddle.net/CbqFv and enter lines until you've got a scrollbar you will see it. Any ideas?Ptolemy
kaljak, does adding overflow: hidden; help? Edit: Wait, that is already there. Then no idea.Floorage
What can I do for prevent scroll bar flashing? If the style overflow:auto;Mini
@Mini Maybe use an visibility:hidden;position:fixed; textarea/div to measure the height? Or use a contentEditable="true"-div instead of a textarea (which complicates other things heavily).Floorage
This breaks completely if the textarea is near the bottom page end - everything jumps back and forward due to style.height='auto'. I suspect the solution is to add a hidden sibling used only for measurement.Bevash
would it hang the browser if pasted large text inside like 3MB file after uploading and getting the response back into the textareaSpoilt
On Firefox 70 it doesn't resize on first character that overflows. On second char it gets resized.Goines
This works fine on JSFuddle, but I'm wondering (as I have such task to do) how it does behave if you increasing and decreasing the font size from the browser settings. Also across different languages?Crespo
E
68

jQuery solution adjust the css to match your requirements

css...

div#container textarea {
    min-width: 270px;
    width: 270px;
    height: 22px;
    line-height: 24px;
    min-height: 22px;
    overflow-y: hidden; /* fixes scrollbar flash - kudos to @brettjonesdev */
    padding-top: 1.1em; /* fixes text jump on Enter keypress */
}

javascript...

// auto adjust the height of
$('#container').delegate( 'textarea', 'keydown', function (){
    $(this).height( 0 );
    $(this).height( this.scrollHeight );
});
$('#container').find( 'textarea' ).keydown();

OR alternative for jQuery 1.7+...

// auto adjust the height of
$('#container').on( 'keyup', 'textarea', function (){
    $(this).height( 0 );
    $(this).height( this.scrollHeight );
});
$('#container').find( 'textarea' ).keyup();

I've created a fiddle with the absolute minimum styling as a starting point for your experiments... http://jsfiddle.net/53eAy/951/

Esprit answered 17/1, 2009 at 22:30 Comment(8)
This is good, but I would add overflow-y: hidden; to the css to prevent the scroll bar from briefly flashing when resize occurs.Cherilyncherilynn
Not entirely sure, but without it the text area grows by too much. I think it's to do with the way that the elements scrollHeight is calculated.Esprit
I like this solution a lot, in the first example, how could I limit the amount of rows and get rid of the padding?Bays
Hi Darius, not sure about getting rid of the padding, tried all kinds of tricks on this, but it's either the padding or the text jump :(. There must be a solution so I'll keep trying. The top answer works well with no padding. Try one of the fiddles in the @ChrisMoschini comment.Esprit
@Bays I'd limit the max rows in the javascript, add the line `if ($(this).height() > maxHeight) { return; } somewhere near the top. You could set overflow-y back to auto to re-instate the scrollbars. You'd need to trigger the function on page load if you conditionally add the scrollbars in.Esprit
Use multiple events to make work for wide verity of scenario $('textarea.auto-resize').on('change cut paste drop keyup', function(){...})Cordwood
Jumps around like crazy in Chrome 40 Win 8.1 on texts longer than the viewport. Renders it quite unusable.Wonderstricken
Holding enter (newline) results in scrolling. The size does not adjust until the key is released.Diametral
C
35

Found an one liner from here;

<textarea name="text" oninput="this.style.height = ''; this.style.height = this.scrollHeight +'px'"></textarea>
Centipede answered 30/12, 2019 at 8:6 Comment(1)
Okay cool but what about the width?Fairing
C
33
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Textarea autoresize</title>
    <style>
    textarea {
        overflow: hidden;
    }
    </style>
    <script>
    function resizeTextarea(ev) {
        this.style.height = '24px';
        this.style.height = this.scrollHeight + 12 + 'px';
    }

    var te = document.querySelector('textarea');
    te.addEventListener('input', resizeTextarea);
    </script>
</head>
<body>
    <textarea></textarea>
</body>
</html>

Tested in Firefox 14 and Chromium 18. The numbers 24 and 12 are arbitrary, test to see what suits you best.

You could do without the style and script tags, but it becomes a bit messy imho (this is old style HTML+JS and is not encouraged).

<textarea style="overflow: hidden" onkeyup="this.style.height='24px'; this.style.height = this.scrollHeight + 12 + 'px';"></textarea>

jsfiddle

Coan answered 24/7, 2012 at 9:48 Comment(5)
This one has some drawbacks: 1) Textarea would not be resized then user paste something with his mouse buttons only; 2) If the user will paste something using keyboard (Ctrl + V) the textarea would be resized only when he will release Ctrl. If the user will press Ctrl + V several times then the textarea will grow only after the last one. You should add same function to paste, cut, change and drop events too.Acey
So just use the input event instead. See https://mcmap.net/q/74847/-textarea-onchange-detectionPlumbo
Improved version with multiple textarea support as a one-liner: document.querySelectorAll('textarea').forEach(function(te){ te.addEventListener("input", function() { this.style.height='24px'; this.style.height=this.scrollHeight+12+'px'; }); });Isley
@Isley It's shorter, but I wouldn't say it's "improved". With an anonymous function, there is no way to call removeEventListener and clean up your event listeners. This is especially important when creating event listeners all over the place in a forEach loop. Plus, in my view, readability is far more important than conciseness.Coan
for others and future me, ensure that box-sizing: border-box; property is set or else the textarea explands by 4px for each onInput event. I spent like 3 hours until i figured out this was the problem.Nigel
C
31

The best solution (works and is short) for me is:

    $(document).on('input', 'textarea', function () {
        $(this).outerHeight(38).outerHeight(this.scrollHeight); // 38 or '1em' -min-height
    }); 

It works like a charm without any blinking with paste (with mouse also), cut, entering and it shrinks to the right size.

Please take a look at jsFiddle.

Cramped answered 29/12, 2015 at 14:49 Comment(5)
Terrific!!! one line deal! silly question ho I can add an animation when the it resizes? like the text box sorta gently resizing rather then the jump to size?Alembic
@Alembic Looks like it's not possible by the design of multi line editing. I made an example of animating textarea size: jsfiddle.net/yk2g333e As you know text cursor goes down at the and of line or caret, so if there is no pause at this moment there is nothing to animate. But pausing will be to annoying for user.Cramped
@Alembic However, with one more empty line at the end of textarea, it's possible to have smooth animation: jsfiddle.net/p23erdfrCramped
Useful tweak for this solution is to also hide vertical scroll-bar (seen in jsFiddle, not mentioned here), you do this with inline styling (style="overflow:hidden") or proper one with: textarea {overflow: hidden;}Pascoe
@Gregor Simončič Yes, especially for a long text -- it gives right calculation of the textarea target height. And also, it’s better for precise calculation to set outerHeight to 0.Cramped
Q
19

If you don’t need to support IE8 you can use the input event:

var resizingTextareas = [].slice.call(document.querySelectorAll('textarea[autoresize]'));

resizingTextareas.forEach(function(textarea) {
  textarea.addEventListener('input', autoresize, false);
});

function autoresize() {
  this.style.height = 'auto';
  this.style.height = this.scrollHeight+'px';
  this.scrollTop = this.scrollHeight;
  window.scrollTo(window.scrollLeft,(this.scrollTop+this.scrollHeight));
}

Now you only need to add some CSS and you are done:

textarea[autoresize] {
  display: block;
  overflow: hidden;
  resize: none;
}

Usage:

<textarea autoresize>Type here and I’ll resize.</textarea>

You can read more about how it works on my blog post.

Quintillion answered 25/7, 2014 at 14:27 Comment(1)
Nice solution, but need little fix. When content of textarea is loaded f.ex. from database, textarea stay small. You have to trigger input event during initialization in foreach cycle.Hunchbacked
D
16

You're using the higher value of the current clientHeight and the content scrollHeight. When you make the scrollHeight smaller by removing content, the calculated area can't get smaller because the clientHeight, previously set by style.height, is holding it open. You could instead take a max() of scrollHeight and a minimum height value you have predefined or calculated from textarea.rows.

In general you probably shouldn't really rely on scrollHeight on form controls. Apart from scrollHeight being traditionally less widely-supported than some of the other IE extensions, HTML/CSS says nothing about how form controls are implemented internally and you aren't guaranteed scrollHeight will be anything meaningful. (Traditionally some browsers have used OS widgets for the task, making CSS and DOM interaction on their internals impossible.) At least sniff for scrollHeight/clientHeight's existance before trying to enable the effect.

Another possible alternative approach to avoid the issue if it's important that it work more widely might be to use a hidden div sized to the same width as the textarea, and set in the same font. On keyup, you copy the text from the textarea to a text node in hidden div (remembering to replace '\n' with a line break, and escape '<'/'&' properly if you're using innerHTML). Then simply measuring the div's offsetHeight will give you the height you need.

Dorsum answered 18/1, 2009 at 0:52 Comment(2)
Which browsers are supposed to have problems with scrollHeight for textareas? Works fine with current versions of IE, Firefox and Opera...Indebtedness
The only one I have to hand is Konqueror, which returns the clientHeight as scrollHeight. This is a behaviour you can expect unless the browser applies the CSS box model to the internals of widgets, something they haven't always done and the standard doesn't say they have to.Dorsum
W
13

autosize

https://github.com/jackmoore/autosize

Just works, standalone, is popular (3.0k+ GitHub stars as of October 2018), available on cdnjs) and lightweight (~3.5k). Demo:

<textarea id="autosize" style="width:200px;">a
J   b
c</textarea>
<script src="https://cdnjs.cloudflare.com/ajax/libs/autosize.js/4.0.2/autosize.min.js"></script>
<script>autosize(document.querySelectorAll('#autosize'));</script>

BTW, if you are using the ACE editor, use maxLines: Infinity: Automatically adjust height to contents in Ace Cloud 9 editor

Wimsatt answered 29/8, 2014 at 10:57 Comment(5)
Version 2 has been released in Feb 2015. It has become simpler and does not depend on jQuery anymoreDerbyshire
Sorry, it does work. Maybe I was in other browser.. so, I think it's better if you ignore my comment..Lamella
@ToniMichelCaubet ah, OK maybe CDN problem then. Let me check.Wimsatt
The autosize plugin does not allow to manually resize using the resize icon in textarea.Stoll
@j4v1, css: #autosize{resize:vertical !important}Fugal
P
10

As a different approach, you can use a <span> which adjusts its size automatically. You will need make it editable by adding the contenteditable="true" property and you're done:

div {
  width: 200px;
}

span {
  border: 1px solid #000;
  padding: 5px;
}
<div>
  <span contenteditable="true">This text can be edited by the user</span>
</div>

The only issue with this approach is that if you want to submit the value as part of the form, you'll have to do so by yourself in JavaScript. Doing so is relatively easy. For example, you can add a hidden field and in the onsubmit event of the form assign the value of the span to the hidden field which will be then automatically submitted with the form.

Plumate answered 24/3, 2018 at 14:40 Comment(2)
There is already an answer using contenteditable on this page: #454702Kirtley
@Kirtley Yes, but the two answers are not the same. Toyota makes red cars, and Ford makes red cars too, but they are different, aren't they? If you like the other answer more, then go with it. But there are those who appreciate my answer more and go with it. Having different options is good.Plumate
F
10

As of 2024, there's a new answer that doesn't need hacks or 3rd party libraries: the field-sizing attribute being added to text inputs as part of web standards. Details in the field-sizing standards proposal explainer.

Update April 2024: for more info, see CSS field-sizing on Chrome dev docs and field-sizing on MDN

With the new field-sizing style, you can instruct <textarea> or <input type="text"> to size themselves based on content:

textarea {
   field-sizing: content;
}

Chromium-based browsers are expected to ship this feature in Chrome 123, expected to arrive March 2024 timeframe.

Here's a quick code snippet to see if your browser supports this new standard:

// Let the user know whether field-sizing is supported.
const textArea = document.querySelector("textarea");
const resultSpan = document.querySelector("span");
resultSpan.innerText = ("fieldSizing" in textArea.style) ? '✅' : '❌'
textarea {
  field-sizing: content;
  min-width: 200px; /* optional: a minimum width, otherwise textarea can become very small with no content */
  max-height: 10lh; /* after 10 lines, give a scrollbar */
}
<textarea>This textarea automatically grows based on its content</textarea>

<h1>Your browser's support for field sizing: <span></span></h1>
Frady answered 11/1 at 23:34 Comment(1)
Worth adding, the standards proposal may add field-sizing to <select>, <input type="number"> and <input type="file"> as well.Frady
S
8

There is a slightly different approach.

<div style="position: relative">
  <pre style="white-space: pre-wrap; word-wrap: break-word"></pre>
  <textarea style="position: absolute; top: 0; left: 0; width: 100%; height: 100%"></textarea>
</div>

The idea is to copy the text from textarea into the pre and let CSS make sure that they have the same size.

The benefit is that frameworks present simple tools to move text around without touching any events. Namely, in AngularJS you would add a ng-model="foo" ng-trim="false" to the textarea and ng-bind="foo + '\n'" to the pre. See a fiddle.

Just make sure that pre has the same font size as the textarea.

Shiner answered 17/7, 2014 at 14:45 Comment(3)
"Just make sure that pre has the same font size as the textarea" - They need the same line-height, and an equal amount of padding and/or border too. This is the best solution for Angular.Debidebilitate
Simple best solution I've seen and tried to come up with for reactive update. Thanks!Garris
Works great in Vue 3 too! Much better than fiddling around with event listeners that you might forget to detach, and jquery. If you are fine-tuning the padding/fonts etc, a good trick is to make the "pre" have color:red, and the "textarea" have opacity:0.5. Thanks!Landsman
H
7

Has anyone considered contenteditable? No messing around with scrolling,a nd the only JS I like about it is if you plan on saving the data on blur... and apparently, it's compatible on all of the popular browsers : http://caniuse.com/#feat=contenteditable

Just style it to look like a text box, and it autosizes... Make its min-height the preferred text height and have at it.

What's cool about this approach is that you can save and tags on some of the browsers.

http://jsfiddle.net/gbutiri/v31o8xfo/

var _auto_value = '';
$(document).on('blur', '.autosave', function(e) {
  var $this = $(this);
  if ($this.text().trim() == '') {
    $this.html('');
  }

  // The text is here. Do whatever you want with it.
  $this.addClass('saving');

  if (_auto_value !== $this.html() || $this.hasClass('error')) {

    // below code is for example only.
    $.ajax({
      url: '/echo/json/?action=xyz_abc',
      data: 'data=' + $this.html(),
      type: 'post',
      datatype: 'json',
      success: function(d) {
        console.log(d);
        $this.removeClass('saving error').addClass('saved');
        var k = setTimeout(function() {
          $this.removeClass('saved error')
        }, 500);
      },
      error: function() {
        $this.removeClass('saving').addClass('error');
      }
    });
  } else {
    $this.removeClass('saving');
  }
}).on('focus mouseup', '.autosave', function() {
  var $this = $(this);
  if ($this.text().trim() == '') {
    $this.html('');
  }
  _auto_value = $this.html();
}).on('keyup', '.autosave', function(e) {
  var $this = $(this);
  if ($this.text().trim() == '') {
    $this.html('');
  }
});
body {
  background: #3A3E3F;
  font-family: Arial;
}

label {
  font-size: 11px;
  color: #ddd;
}

.autoheight {
  min-height: 16px;
  font-size: 16px;
  margin: 0;
  padding: 10px;
  font-family: Arial;
  line-height: 20px;
  box-sizing: border-box;
  -o-box-sizing: border-box;
  -moz-box-sizing: border-box;
  -webkit-box-sizing: border-box;
  overflow: hidden;
  display: block;
  resize: none;
  border: 0;
  outline: none;
  min-width: 200px;
  background: #ddd;
  max-height: 400px;
  overflow: auto;
}

.autoheight:hover {
  background: #eee;
}

.autoheight:focus {
  background: #fff;
}

.autosave {
  -webkit-transition: all .2s;
  -moz-transition: all .2s;
  transition: all .2s;
  position: relative;
  float: none;
}

.autoheight * {
  margin: 0;
  padding: 0;
}

.autosave.saving {
  background: #ff9;
}

.autosave.saved {
  background: #9f9;
}

.autosave.error {
  background: #f99;
}

.autosave:hover {
  background: #eee;
}

.autosave:focus {
  background: #fff;
}

[contenteditable=true]:empty:before {
  content: attr(placeholder);
  color: #999;
  position: relative;
  top: 0px;
  /*
    For IE only, do this:
    position: absolute;
    top: 10px;
    */
  cursor: text;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<label>Your Name</label>
<div class="autoheight autosave contenteditable" contenteditable="true" placeholder="Your Name"></div>
Hydromancy answered 16/10, 2014 at 20:9 Comment(3)
Chrome will add <div> elements on ENTER.Est
contenteditable is good, but if you want plaintext it needs a bunch of options like -webkit-user-modify: read-write-plaintext-only and white-space: pre-wrap.Ostrogoth
@_sbaechler: the <div>s are omitted when using [dom-element].innerText. @WebmasterG IMHO it would be nice to omit jquery (for transparency) and to include the example on this page via runnable Code Snippet instead of on jsfiddle.Kirtley
F
6

The following works for cutting, pasting, etc., regardless of whether those actions are from the mouse, a keyboard shortcut, selecting an option from a menu bar ... several answers take a similar approach but they don't account for box-sizing, which is why they incorrectly apply the style overflow: hidden.

I do the following, which also works well with max-height and rows for minimum and maximum height.

function adjust() {
  var style = this.currentStyle || window.getComputedStyle(this);
  var boxSizing = style.boxSizing === 'border-box'
      ? parseInt(style.borderBottomWidth, 10) +
        parseInt(style.borderTopWidth, 10)
      : 0;
  this.style.height = '';
  this.style.height = (this.scrollHeight + boxSizing) + 'px';
};

var textarea = document.getElementById("ta");
if ('onpropertychange' in textarea) { // IE
  textarea.onpropertychange = adjust;
} else if ('oninput' in textarea) {
  textarea.oninput = adjust;
}
setTimeout(adjust.bind(textarea));
textarea {
  resize: none;
  max-height: 150px;
  border: 1px solid #999;
  outline: none;
  font: 18px sans-serif;
  color: #333;
  width: 100%;
  padding: 8px 14px;
  box-sizing: border-box;
}
<textarea rows="3" id="ta">
Try adding several lines to this.
</textarea>

For absolute completeness, you should call the adjust function in a few more circumstances:

  1. Window resize events, if the width of the textarea changes with window resizing, or other events that change the width of the textarea
  2. When the textarea's display style attribute changes, e.g. when it goes from none (hidden) to block
  3. When the value of the textarea is changed programmatically

Note that using window.getComputedStyle or getting currentStyle can be somewhat computationally expensive, so you may want to cache the result instead.

Works for IE6, so I really hope that's good enough support.

Furry answered 1/5, 2017 at 3:1 Comment(0)
A
5

I used the following code for multiple textareas. Working fine in Chrome 12, Firefox 5 and IE 9, even with delete, cut and paste actions performed in the textareas.

function attachAutoResizeEvents() {
  for (i = 1; i <= 4; i++) {
    var txtX = document.getElementById('txt' + i)
    var minH = txtX.style.height.substr(0, txtX.style.height.indexOf('px'))
    txtX.onchange = new Function("resize(this," + minH + ")")
    txtX.onkeyup = new Function("resize(this," + minH + ")")
    txtX.onchange(txtX, minH)
  }
}

function resize(txtX, minH) {
  txtX.style.height = 'auto' // required when delete, cut or paste is performed
  txtX.style.height = txtX.scrollHeight + 'px'
  if (txtX.scrollHeight <= minH)
    txtX.style.height = minH + 'px'
}
window.onload = attachAutoResizeEvents
textarea {
  border: 0 none;
  overflow: hidden;
  outline: none;
  background-color: #eee
}
<textarea style='height:100px;font-family:arial' id="txt1"></textarea>
<textarea style='height:125px;font-family:arial' id="txt2"></textarea>
<textarea style='height:150px;font-family:arial' id="txt3"></textarea>
<textarea style='height:175px;font-family:arial' id="txt4"></textarea>
Agace answered 23/6, 2011 at 15:10 Comment(0)
G
5

A simple way to do using React.

...
const textareaRef = useRef();

const handleChange = (e) => {
  textareaRef.current.style.height = "auto";
  textareaRef.current.style.height = textareaRef.current.scrollHeight + "px";
};

return <textarea ref={textareaRef} onChange={handleChange} />;
Grey answered 25/3, 2022 at 21:54 Comment(4)
It won't work on mount though.Methodist
@AlanJereb maybe you could use 'useLayoutEffect' for it.Grey
good solution, but if your textarea is initially short and placed anywhere on the lower side of the screen, the whole page starts jumping upwards everytime you type somethingJonson
@Jonson is it possible you add this issue in the codesandbox? to investigate this issueGrey
I
4

A bit corrections. Works perfectly in Opera

  $('textarea').bind('keyup keypress', function() {
      $(this).height('');
      var brCount = this.value.split('\n').length;
      this.rows = brCount+1; //++ To remove twitching
      var areaH = this.scrollHeight,
          lineHeight = $(this).css('line-height').replace('px',''),
          calcRows = Math.floor(areaH/lineHeight);
      this.rows = calcRows;
  });
Intervene answered 19/6, 2011 at 12:14 Comment(1)
works as long as your lines don't overflow - then they won't fit.Ruling
O
4

Some of the answers here don't account for padding.

Assuming you have a maxHeight you don't want to go over, this worked for me:

    // obviously requires jQuery

    // element is the textarea DOM node

    var $el = $(element);
    // inner height is height + padding
    // outerHeight includes border (and possibly margins too?)
    var padding = $el.innerHeight() - $el.height();
    var originalHeight = $el.height();

    // XXX: Don't leave this hardcoded
    var maxHeight = 300;

    var adjust = function() {
        // reset it to the original height so that scrollHeight makes sense
        $el.height(originalHeight);

        // this is the desired height (adjusted to content size)
        var height = element.scrollHeight - padding;

        // If you don't want a maxHeight, you can ignore this
        height = Math.min(height, maxHeight);

        // Set the height to the new adjusted height
        $el.height(height);
    }

    // The input event only works on modern browsers
    element.addEventListener('input', adjust);
Originate answered 1/6, 2013 at 12:51 Comment(0)
R
4

I Don't know if anyone mention this way but in some cases it's possible to resize the height with rows Attribute

textarea.setAttribute('rows',breaks);

Demo

Rickyrico answered 11/11, 2014 at 12:48 Comment(1)
That works only if you have white-space: nowrap;. When a line wraps to another line without line-break, the textarea will not be adjusted properly anymore.Goddaughter
J
4

Here is an angularjs directive for panzi's answer.

 module.directive('autoHeight', function() {
        return {
            restrict: 'A',
            link: function(scope, element, attrs) {
                element = element[0];
                var resize = function(){
                    element.style.height = 'auto';
                    element.style.height = (element.scrollHeight)+'px';
                };
                element.addEventListener('change', resize, false);
                element.addEventListener('cut',    resize, false);
                element.addEventListener('paste',  resize, false);
                element.addEventListener('drop',   resize, false);
                element.addEventListener('keydown',resize, false);

                setTimeout(resize, 100);
            }
        };
    });

HTML:

<textarea ng-model="foo" auto-height></textarea>
Jake answered 29/8, 2017 at 20:8 Comment(1)
You should rather use $timeout than setTimout - this will make sure that the model gets initialised (no need to specify milliseconds - it will get executed after Angular digest cycle). Also element = element[0]; is a very bad practise... Anyway, the solution is no good for me as I need the textarea to be one-line untill there's more text.Alcestis
C
4

You can use JQuery to expand the textarea while typing:

$(document).find('textarea').each(function () {
  var offset = this.offsetHeight - this.clientHeight;

  $(this).on('keyup input focus', function () {
    $(this).css('height', 'auto').css('height', this.scrollHeight + offset);
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div>
<textarea name="note"></textarea>
<div>
Consume answered 28/11, 2018 at 0:10 Comment(1)
Cleanest solution. but as we should stop using jQuery: textarea.addEventListener('keyup', () => { textarea.style.height = 0; textarea.style.height = ${textarea.scrollHeight}px; });Lamella
G
3

I know a short and correct way of implementing this with jquery.No extra hidden div needed and works in most browser

<script type="text/javascript">$(function(){
$("textarea").live("keyup keydown",function(){
var h=$(this);
h.height(60).height(h[0].scrollHeight);//where 60 is minimum height of textarea
});});

</script>
Grani answered 24/5, 2012 at 8:46 Comment(1)
jQuery's .live() has been deprecated. api.jquery.com/live You'll generally want to use .on() instead.Hop
S
3

An even simpler, cleaner approach is this:

// adjust height of textarea.auto-height
$(document).on( 'keyup', 'textarea.auto-height', function (e){
    $(this).css('height', 'auto' ); // you can have this here or declared in CSS instead
    $(this).height( this.scrollHeight );
}).keyup();

// and the CSS

textarea.auto-height {
    resize: vertical;
    max-height: 600px; /* set as you need it */
    height: auto;      /* can be set here of in JS */
    overflow-y: auto;
    word-wrap:break-word
}

All that is needed is to add the .auto-height class to any textarea you want to target.

Tested in FF, Chrome and Safari. Let me know if this doesn't work for you, for any reason. But, this is the cleanest and simplest way I've found this to work. And it works great! :D

Sarene answered 31/7, 2014 at 20:58 Comment(1)
Do you tried to remove text after editing? Did the textarea collapse?Blackmarket
N
3

Those who want to achieve the same in new versions of Angular.

Grab textArea elementRef.

@ViewChild('textArea', { read: ElementRef }) textArea: ElementRef;

public autoShrinkGrow() {
    textArea.style.overflow = 'hidden';
    textArea.style.height = '0px';
    textArea.style.height = textArea.scrollHeight + 'px';
}

<textarea (keyup)="autoGrow()" #textArea></textarea>

I am also adding another use case that may come handy some users reading the thread, when user want to increase the height of text-area to certain height and then have overflow:scroll on it, above method can be extended to achieve the mentioned use-case.

  public autoGrowShrinkToCertainHeight() {
    const textArea = this.textArea.nativeElement;
    if (textArea.scrollHeight > 77) {
      textArea.style.overflow = 'auto';
      return;
    }
    else {
      textArea.style.overflow = 'hidden';
      textArea.style.height = '0px';
      textArea.style.height = textArea.scrollHeight + 'px';
    }
  }
Numerary answered 15/4, 2019 at 16:52 Comment(0)
D
3

my implementation is very simple, count the number of lines in the input (and minimum 2 rows to show that it's a textarea):

textarea.rows = Math.max(2, textarea.value.split("\n").length) // # oninput

full working example with stimulus: https://jsbin.com/kajosolini/1/edit?html,js,output

(and this works with the browser's manual resize handle for instance)

Degrade answered 9/5, 2019 at 15:55 Comment(1)
This only works if you break the line by pressing "enter". If you text is longer than the textarea's width but you don't hit "enter", it doesn't expand.Isotropic
S
3

Improved responsive pure JS solution with @DreamTeK's second option as basis

The following also takes care of the bottom padding as well as window resize. Like this, it's a near perfect solution for me. Big thanks to him.

let textareas = document.getElementsByClassName("auto-resize-textarea");

// Loop through textareas and add event listeners as well as other needed css attributes
for (const textarea of textareas) {
    // Initially set height as otherwise the textarea is not high enough on load
    textarea.style.height = textarea.scrollHeight.toString();
    // Hide scrollbar
    textarea.style.overflowY = 'hidden';
    // Call resize function with "this" context once during initialisation as it's too high otherwise
    resizeTextarea.call(textarea);
    // Add event listener to resize textarea on input
    textarea.addEventListener('input', resizeTextarea, false);
    // Also resize textarea on window resize event binding textarea to be "this"
    window.addEventListener('resize', resizeTextarea.bind(textarea), false);
}
function resizeTextarea() {
    // Textareas have default 2px padding and if not set it returns 0px
    let padding = window.getComputedStyle(this).getPropertyValue('padding-bottom');
    // getPropertyValue('padding-bottom') returns "px" at the end it needs to be removed to be added to scrollHeight
    padding = parseInt(padding.replace('px',''));
    this.style.height = "auto";
    this.style.height = (this.scrollHeight) + "px";
}
textarea {
  width:40%;
  padding:20px 25px;
  border-radius: 20px;
}
<textarea class="auto-resize-textarea">Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.</textarea>
<textarea placeholder="Type, paste, cut text here..." class="auto-resize-textarea"></textarea>

Note: there is a weird issue with jsfiddle where the textarea is too high and there is too much space at the bottom, but copying and pasting this exact code to an empty HTML-file works perfectly.

There is a small issue though when a scrollbar appears on the page and the textarea shrinks and wraps the text and creates a new line. The above function does not take that into account and I made a question, but no-one seems to know a fix. If you have suggestions to resolve the issue, I would be very glad.

Syndic answered 24/8, 2022 at 11:9 Comment(0)
D
2

This code works for pasting and select delete also.

onKeyPressTextMessage = function(){
			var textArea = event.currentTarget;
    	textArea.style.height = 'auto';
    	textArea.style.height = textArea.scrollHeight + 'px';
};
<textarea onkeyup="onKeyPressTextMessage(event)" name="welcomeContentTmpl" id="welcomeContent" onblur="onblurWelcomeTitle(event)" rows="2" cols="40" maxlength="320"></textarea>

Here is the JSFiddle

Disappoint answered 12/9, 2016 at 6:1 Comment(0)
E
2

I recommend the javascript library from http://javierjulio.github.io/textarea-autosize.

Per comments, add example codeblock on plugin usage:

<textarea class="js-auto-size" rows="1"></textarea>

<script src="http://code.jquery.com/jquery-2.1.0.min.js"></script>
<script src="jquery.textarea_autosize.min.js"></script>
<script>
$('textarea.js-auto-size').textareaAutoSize();
</script>

Minimum required CSS:

textarea {
  box-sizing: border-box;
  max-height: 160px; // optional but recommended
  min-height: 38px;
  overflow-x: hidden; // for Firefox (issue #5)
}
Electrothermics answered 1/3, 2017 at 8:59 Comment(0)
B
2

None of the answers seem to work. But this one works for me: https://coderwall.com/p/imkqoq/resize-textarea-to-fit-content

$('#content').on( 'change keyup keydown paste cut', 'textarea', function (){
    $(this).height(0).height(this.scrollHeight);
}).find( 'textarea' ).change();
Bare answered 23/5, 2018 at 8:45 Comment(1)
This should be the accepted answer, though it's enough to listen to "keyup" eventsKillie
Q
2

MakeTextAreaResisable that uses qQuery

function MakeTextAreaResisable(id) {
    var o = $(id);
    o.css("overflow-y", "hidden");

    function ResizeTextArea() {
        o.height('auto');
        o.height(o[0].scrollHeight);
    }

    o.on('change', function (e) {
        ResizeTextArea();
    });

    o.on('cut paste drop keydown', function (e) {
        window.setTimeout(ResizeTextArea, 0);
    });

    o.focus();
    o.select();
    ResizeTextArea();
}
Quinn answered 19/6, 2018 at 18:1 Comment(0)
M
2

Accepted answer is working fine. But that is lot of code for this simple functionality. The below code will do the trick.

   $(document).on("keypress", "textarea", function (e) {
    var height = $(this).css("height");
    var iScrollHeight = $(this).prop("scrollHeight");
    $(this).css('height',iScrollHeight);
    });
Manara answered 5/3, 2020 at 13:46 Comment(0)
R
2

An example implementation with React:

const {
  useLayoutEffect,
  useState,
  useRef
} = React;

const TextArea = () => {
  const ref = useRef();
  const [value, setValue] = useState('Some initial text that both wraps and uses\nnew\nlines');

  // This only tracks the auto-sized height so we can tell if the user has manually resized
  const autoHeight = useRef();

  useLayoutEffect(() => {
    if (!ref.current) {
      return;
    }

    if (
      autoHeight.current !== undefined &&
      ref.current.style.height !== autoHeight.current
    ) {
      // don't auto size if the user has manually changed the height
      return;
    }

    ref.current.style.height = "auto";
    ref.current.style.overflow = "hidden";
    const next = `${ref.current.scrollHeight}px`;
    ref.current.style.height = next;
    autoHeight.current = next;
    ref.current.style.overflow = "auto";
  }, [value, ref, autoHeight]);


  return (
    <textarea
      ref={ref}
      style={{
        resize: 'vertical',
        minHeight: '1em',
      }}
      value={value}
      onChange={event => setValue(event.target.value)}
    />
  );
}

ReactDOM.render(<TextArea />, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="app"></div>
Ragsdale answered 3/8, 2021 at 15:36 Comment(0)
U
2

Dynamic textArea using pure css:

if you want to use only css you can also create your element like this:

function contentTransfer(){
  document.getElementsByClassName("container")[0].innerHTML = document.getElementById("myTextArea").innerHTML;
}
.custom_textArea{
  border: 1px solid lightGray;
  padding: 7px;
  border-radius: 7px;
  outline: none;
}

.custom_textArea:focus{
  border: 1px solid darkGray;
}
<p id="myTextArea" class="custom_textArea" contenteditable="true">my text</p>
<button onclick="contentTransfer()">get content</button>
<p class="container"></p>
Unbated answered 27/8, 2023 at 4:32 Comment(1)
and if you want to use it with a form that html itself submit it you can use a hidden input or` textarea` and <button onclick='document.getElementById("your input ID or text area ID").value= document.getElementById("myTextArea").innerHTML; document.getElementById("your form ID").submit()'>submit</button> as your submit button.Unbated
P
1

If scrollHeight could be trusted, then:

textarea.onkeyup=function() {
  this.style.height='';
  this.rows=this.value.split('\n').length;
  this.style.height=this.scrollHeight+'px';
}
Predispose answered 1/10, 2010 at 23:34 Comment(2)
this.rows=this.value.split('\n').length; This wouldn't work. Because number of lines in the text is not equal to count of \n. You haven't considered textwrap.Dianthe
@EasternMonk if you try it it actually works well and is quite intuitive IMHO: jsbin.com/tilokafasa/1/edit?html,js,outputDegrade
B
1

I wanna use this

window.auto_grow = async element => {
    element.style.height = "5px";
    element.style.height = (element.scrollHeight) + "px";
}

and call it

<textarea oninput="window.auto_grow(this)" onfocus="window.auto_grow(this)"></textarea>
Brine answered 12/4, 2023 at 13:24 Comment(0)
B
0

Here is what I did while using MVC HTML Helper for TextArea. I had quite a few of textarea elements so had to distinguish them using Model Id.

 @Html.TextAreaFor(m => m.Text, 2, 1, new { id = "text" + Model.Id, onkeyup = "resizeTextBox(" + Model.Id + ");" })

and in script added this:

   function resizeTextBox(ID) {            
        var text = document.getElementById('text' + ID);
        text.style.height = 'auto';
        text.style.height = text.scrollHeight + 'px';            
    }

I have tested it on IE10 and Firefox23

Buiron answered 11/9, 2013 at 13:38 Comment(0)
B
0

Native Javascript solution without flickering in Firefox and faster than method withclientHeight...

1) Add div.textarea selector to all your selectors containing textarea. Do not forget to add box-sizing: border-box;

2) Include this script:

function resizeAll()
{
   var textarea=document.querySelectorAll('textarea');
   for(var i=textarea.length-1; i>=0; i--)
      resize(textarea[i]);
}

function resize(textarea)
{
   var div = document.createElement("div");
   div.setAttribute("class","textarea");
   div.innerText=textarea.value+"\r\n";
   div.setAttribute("style","width:"+textarea.offsetWidth+'px;display:block;height:auto;left:0px;top:0px;position:fixed;z-index:-200;visibility:hidden;word-wrap:break-word;overflow:hidden;');
   textarea.form.appendChild(div);
   var h=div.offsetHeight;
   div.parentNode.removeChild(div);
   textarea.style.height=h+'px';
}

function resizeOnInput(e)
{
   var textarea=document.querySelectorAll('textarea');
   for(var i=textarea.length-1; i>=0; i--)
      textarea[i].addEventListener("input",function(e){resize(e.target); return false;},false);
}

window.addEventListener("resize",function(){resizeAll();}, false);
window.addEventListener("load",function(){resizeAll();}, false);
resizeOnInput();

Tested on IE11, Firefox and Chrome.

This solution creates div similar to your textarea including internal text and measures height.

Blackmarket answered 18/11, 2017 at 5:49 Comment(0)
B
0

The Best way I found:

$("textarea.auto-grow").each( function(){
    $(this).keyup(function(){
        $(this).height( $(this)[0].scrollHeight - Number( $(this).css("font-size").replace("px", "") ) );
    });
});

Other ways has a font-size bug.

Thats why this is the best.

Browbeat answered 17/1, 2019 at 17:47 Comment(0)
C
0

This is a mixed JS/jQuery version of Moussawi7's answer.

$(function() {
  $("textarea.auto-grow").on("input", function() {
    var element = $(this)[0];
    element.style.height = "5px";
    element.style.height = (element.scrollHeight) + "px";
  });
});

And this one is Mystral's comment. It's more like jquery code.

$(function() {
  $("textarea.auto-grow").on("input", function() {
    $(this).css("height", "5px")
           .css("height", $(this).prop("scrollHeight") + "px");
  });
});

CSS:

<style>
  textarea {
    resize: none;
    overflow: auto;
    width: 100%;
    min-height: 50px;
    max-height: 150px;
  }
</style>

Html:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<textarea class="auto-grow"></textarea>
Chloramine answered 16/8, 2020 at 0:4 Comment(2)
Full Jquery : $(function() { $("textarea.auto-grow").on("input", function() { $(this).css("height","5px").css("height",$(this).prop("scrollHeight")+"px") }); })Byrle
@Mystral, thanks. It's more like jquery. I added also your code too.Chloramine
S
0

for Angular 2+, just do this

<textarea (keydown)="resize($event)"></textarea>


resize(e) {
    setTimeout(() => {
      e.target.style.height = 'auto';
      e.target.style.height = (e.target.scrollHeight)+'px';
    }, 0);
  }

textarea {
  resize: none;
  overflow: hidden;
}
Sternick answered 6/10, 2020 at 14:18 Comment(0)
D
0

I think this answer is almost more complete and correct because it uses the rows property of the textarea:

function addLiveAutoHeight(id, maxHeight=10) {
    const tag = document.getElementById(id);
    if(!Number.isInteger(maxHeight)){
        tag.style.maxHeight = maxHeight;
        maxHeight = 999999999;
    }
    tag.rows = Math.min(maxHeight,tag.value.split("\n").length);
    document.getElementById(id).oninput = function () {
        this.rows = Math.min(maxHeight,this.value.split("\n").length);
    }
}

and to use:

addLiveAutoHeight("MY_TEXTAREA_ID");

Enjoy...

Dyaus answered 21/9, 2023 at 10:40 Comment(0)
S
0

If you don't want to shift around things while the user is typing, you could just resize it when the user leaves (blur), or maybe other appropriate events. That's what did it for me:

shrinkOnBlur(event) {
    setTimeout(function () {
        event.target.rows = 1;
        while (event.target.scrollHeight > event.target.clientHeight) {
            event.target.rows++;
        }
    }, 100);
}

Possibly you can add some space on focus (which is removed again on blur).

Stratagem answered 22/9, 2023 at 6:7 Comment(0)
F
0

If you are using react I would recommend TextareaAutosize library. It's nothing but simple textarea under the hood but frees you of the hassles of styling issues and if you are already using the styling for textarea then you dont need to add any additional styling either.

on terminal:

npm install react-textarea-autosize

in code:

import TextareaAutosize from 'react-textarea-autosize';

// If you use CommonJS syntax:
// var TextareaAutosize = require('react-textarea-autosize').default;

React.renderComponent(
  <div>
    <TextareaAutosize />
  </div>,
  document.getElementById('element'),
);
Fleabitten answered 29/2 at 23:51 Comment(0)
B
0

for Vue2 directives:

directives: {
  autoResize: {
    // autoResize
    inserted: (el) => {
      function OnInput() {
        el.style.height = 'auto';
        el.style.height = (this.scrollHeight) + "px";
      }
      el.setAttribute("style", "height:" + (el.scrollHeight) + "px;overflow-y:hidden;");
      el.addEventListener("input", OnInput, false);
    }
  }
}
Bravar answered 10/4 at 7:56 Comment(0)
H
-1

I have tested script in common browsers, and it failed in Chrome and Safari. It is because of constantly updatable scrollHeight variable.

I have applied DisgruntledGoat script using jQuery and added chrome fix

function fitToContent(/* JQuery */text, /* Number */maxHeight) {
    var adjustedHeight = text.height();
    var relative_error = parseInt(text.attr('relative_error'));
    if (!maxHeight || maxHeight > adjustedHeight) {
        adjustedHeight = Math.max(text[0].scrollHeight, adjustedHeight);
        if (maxHeight)
            adjustedHeight = Math.min(maxHeight, adjustedHeight);
        if ((adjustedHeight - relative_error) > text.height()) {
            text.css('height', (adjustedHeight - relative_error) + "px");
            // chrome fix
            if (text[0].scrollHeight != adjustedHeight) {
                var relative = text[0].scrollHeight - adjustedHeight;
                if (relative_error != relative) {
                    text.attr('relative_error', relative + relative_error);
                }
            }
        }
    }
}

function autoResizeText(/* Number */maxHeight) {
    var resize = function() {
        fitToContent($(this), maxHeight);
    };
    $("textarea").attr('relative_error', 0);
    $("textarea").each(resize);
    $("textarea").keyup(resize).keydown(resize);
}
Headlight answered 7/9, 2009 at 14:1 Comment(0)
D
-1
$('textarea').bind('keyup change', function() {
    var $this = $(this), $offset = this.offsetHeight;
    $offset > $this.height() && $offset < 300 ?
        $this.css('height ', $offset)
            .attr('rows', $this.val().split('\n').length)
            .css({'height' : $this.attr('scrollHeight'),'overflow' : 'hidden'}) :
        $this.css('overflow','auto');
});
Determinable answered 17/2, 2011 at 10:14 Comment(0)
M
-1

I'm able to set the TextArea size in IE9 and Chrome with the following jQuery function. It binds to the textarea objects from the selector defined in the $(document).ready() function.

function autoResize(obj, size) {
    obj.keyup(function () {
        if ($(this).val().length > size-1) {
            $(this).val( function() {
                $(this).height(function() {
                    return this.scrollHeight + 13;
                });
                alert('The maximum comment length is '+size+' characters.');
                return $(this).val().substring(0, size-1);
            });
        }
        $(this).height(function() {
            if  ($(this).val() == '') {
                return 15;
            } else {
                $(this).height(15);
                return ($(this).attr('scrollHeight')-2);
            }
        });
    }).keyup();
}

In my $(document).ready() function I have the following call for all of my textarea calls on this page.

$('textarea').each( function() {
        autoResize($(this), 250);
});

Where 250 is the character limit on my text area. This will grow as large as the text size will allow (based on your character count and font size). It will also shrink your text area appropriately when you remove characters from your textarea or if the user pastes too much text initially.

Milo answered 9/5, 2012 at 21:57 Comment(0)
S
-1

You can use this code:

Coffescript:

jQuery.fn.extend autoHeightTextarea: ->
  autoHeightTextarea_ = (element) ->
    jQuery(element).css(
      'height': 'auto'
      'overflow-y': 'hidden').height element.scrollHeight

  @each ->
    autoHeightTextarea_(@).on 'input', ->
      autoHeightTextarea_ @

$('textarea_class_or_id`').autoHeightTextarea()

Javascript

jQuery.fn.extend({
  autoHeightTextarea: function() {
    var autoHeightTextarea_;
    autoHeightTextarea_ = function(element) {
      return jQuery(element).css({
        'height': 'auto',
        'overflow-y': 'hidden'
      }).height(element.scrollHeight);
    };
    return this.each(function() {
      return autoHeightTextarea_(this).on('input', function() {
        return autoHeightTextarea_(this);
      });
    });
  }
});

$('textarea_class_or_id`').autoHeightTextarea();
Sutphin answered 8/6, 2015 at 15:3 Comment(0)
F
-1

For those who want the textarea to be auto resized on both width and height:

HTML:

<textarea class='textbox'></textarea>
<div>
  <span class='tmp_textbox'></span>
</div>

CSS:

.textbox,
.tmp_textbox {
  font-family: 'Arial';
  font-size: 12px;
  resize: none;
  overflow:hidden;
}

.tmp_textbox {
  display: none;
}

jQuery:

$(function(){
  //alert($('.textbox').css('padding'))
  $('.textbox').on('keyup change', checkSize)
  $('.textbox').trigger('keyup')

  function checkSize(){
    var str = $(this).val().replace(/\r?\n/g, '<br/>');
    $('.tmp_textbox').html( str )
    console.log($(this).val())

    var strArr = str.split('<br/>')
    var row = strArr.length
    $('.textbox').attr('rows', row)
    $('.textbox').width( $('.tmp_textbox').width() + parseInt($('.textbox').css('padding')) * 2 + 10 )
  }
})

Codepen:

http://codepen.io/anon/pen/yNpvJJ

Cheers,

Frost answered 29/6, 2015 at 4:51 Comment(0)
A
-1

The jQuery solution is to set the height of the textarea to 'auto', check the scrollHeight and then adapt the height of the textarea to that, every time a textarea changes (JSFiddle):

$('textarea').on( 'input', function(){
    $(this).height( 'auto' ).height( this.scrollHeight );
});

If you're dynamically adding textareas (through AJAX or whatever), you can add this in your $(document).ready to make sure all textareas with class 'autoheight' are kept to the same height as their content:

$(document).on( 'input', 'textarea.autoheight', function() {
    $(this).height( 'auto' ).height( this.scrollHeight );
});

Tested and working in Chrome, Firefox, Opera and IE. Also supports cut and paste, long words, etc.

Aceves answered 2/7, 2016 at 10:15 Comment(2)
If you're loading a text-area with initial content through AJAX you may want to trigger an 'input' to make sure the height is correct on init, so after loading the textarea, call $( 'textarea' ).trigger( 'input' );Aceves
Don't know why this is downvoted. It's a working solution which we still use today, 7 years after we uploaded itAceves
Y
-1

You can use this piece of code to compute the number of rows a textarea needs:

textarea.rows = 1;
    if (textarea.scrollHeight > textarea.clientHeight)
      textarea.rows = textarea.scrollHeight / textarea.clientHeight;

Compute it on input and window:resize events to get auto-resize effect. Example in Angular:

Template code:

<textarea rows="1" reAutoWrap></textarea>

auto-wrap.directive.ts

import { Directive, ElementRef, HostListener } from '@angular/core';

@Directive({
  selector: 'textarea[reAutoWrap]',
})
export class AutoWrapDirective {

  private readonly textarea: HTMLTextAreaElement;

  constructor(el: ElementRef) {
    this.textarea = el.nativeElement;
  }

  @HostListener('input') onInput() {
    this.resize();
  }

  @HostListener('window:resize') onChange() {
    this.resize();
  }

  private resize() {
    this.textarea.rows = 1;
    if (this.textarea.scrollHeight > this.textarea.clientHeight)
      this.textarea.rows = this.textarea.scrollHeight / this.textarea.clientHeight;
  }

}
Yasmineyasu answered 14/3, 2017 at 13:22 Comment(0)
V
-1

You don't need overly complicated calculations or style manipulations. Here is a clear and concise way to do it:

  1. Add oninput event listener to the textarea element.
  2. Inside that listener, set rows attribute via currentTarget

const el = document.createElement('textarea');

const handleInput = (event) => {
  const lines = event.currentTarget.value.split(/\r\n|\r|\n/).length
  event.currentTarget.setAttribute('rows', lines.toString());
}

el.addEventListener('input', handleInput);

document.body.appendChild(el);

You can control the initial height using the very same way:

  1. Get the content
  2. Calculate the number of lines
  3. Set the rows attribute on the element.
const el = document.createElement('textarea');

const content = 'Some Content';
const lines = content.split(/\r\n|\r|\n/).length
el.setAttribute('rows', lines.toString());
el.innerHTML = content;
Vacuity answered 3/4, 2023 at 20:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.