514

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 )
    };
}
Racil Hilan
  • 24,690
  • 13
  • 50
  • 55
DisgruntledGoat
  • 70,219
  • 68
  • 205
  • 290
  • possible duplicate of [Autosizing textarea using prototype](http://stackoverflow.com/questions/7477/autosizing-textarea-using-prototype) – Ciro Santilli OurBigBook.com Aug 27 '14 at 14:28
  • I created a package for this if you are using react: https://www.npmjs.com/package/react-fluid-textarea – Martin Dawson Dec 03 '17 at 00:08
  • Sort and Sweet answer here : https://stackoverflow.com/a/995374/5114465 `function textAreaAdjust(o) { o.style.height = "1px"; o.style.height = (25+o.scrollHeight)+"px"; } ` ` ` – Shurvir Mori Jan 04 '20 at 12:06
  • Using CSS (and a wrapper element) only: https://css-tricks.com/the-cleanest-trick-for-autogrowing-textareas/ – Bergi Feb 09 '22 at 12:47

47 Answers47

637

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 textarea's (multiline textbox's) 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 = 0;
  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 = 0;
  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>
DreamTeK
  • 32,537
  • 27
  • 112
  • 171
  • 13
    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. – Chris Marisic Oct 03 '14 at 15:34
  • 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. lol – WTIFS Aug 30 '16 at 09:44
  • @WTIFS 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. – DreamTeK Aug 30 '16 at 10:47
  • 1
    @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. – WTIFS Aug 30 '16 at 10:56
  • @WTIFS 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. http://jsfiddle.net/n9uuv0hd/8/ – DreamTeK Aug 30 '16 at 12:23
  • 5
    @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 – WTIFS Aug 31 '16 at 04:03
  • 10
    @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. – Modular Sep 29 '16 at 16:49
  • 8
    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. – ZorroDeLaArena Sep 30 '16 at 14:08
  • 3
    @Obsidian Can you explain how `this.style.height = 'auto';` fixes the behaviour of scrollHeight? It's just magic. – sidney Aug 25 '17 at 06:05
  • 3
    @sidney 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`. – DreamTeK Aug 25 '17 at 08:14
  • 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. –  Sep 03 '17 at 12:25
  • @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. – DreamTeK Sep 04 '17 at 08:08
  • @Obsidian Have you tried using the textara with text spanning more than 100% screen height? Then the first glitch occurs, –  Sep 04 '17 at 08:39
  • @Soaku yes, http://jsfiddle.net/n9uuv0hd/94/ works fine in chrome and operates as textarea home end in firefox. Can you create a fiddle with your problem? – DreamTeK Sep 04 '17 at 09:12
  • @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. –  Sep 04 '17 at 09:24
  • @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? – sidney Jan 11 '18 at 04:27
  • 1
    @sidney 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! – DreamTeK Jan 11 '18 at 11:30
  • 1
    elem[0].scrollHeight may help for the case elem.scrollHeight does not work – bbe Jan 29 '18 at 11:41
  • 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 called – Kittichote Chain Sep 18 '19 at 10:13
  • @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. – DreamTeK Sep 19 '19 at 07:43
  • @DreamTeK 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 https://stackoverflow.com/questions/58008393/how-to-make-input-fields-height-responsive-to-the-content – Kittichote Chain Sep 19 '19 at 09:56
  • 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. – Vincent Jan 02 '20 at 17:39
  • @Vincent 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. – DreamTeK Jan 03 '20 at 09:07
  • 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... – Fla Apr 24 '20 at 22:19
  • 1
    @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 http://jsfiddle.net/fxre1zm5/ – DreamTeK Apr 29 '20 at 10:56
  • 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. – Fla May 01 '20 at 11:44
  • @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? – DreamTeK May 04 '20 at 09:25
  • 2
    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'; – dimson d May 13 '20 at 16:04
  • 1
    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. –  Feb 21 '21 at 19:28
  • 2
    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. – Chris Sep 09 '21 at 21:12
  • 1
    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. http://jsfiddle.net/L8259hod/ – daamsie Sep 24 '21 at 03:23
  • 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. – Sam Bayer Oct 19 '21 at 16:05
  • @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. – DreamTeK Oct 21 '21 at 07:25
  • 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? – Yooric Feb 18 '22 at 13:53
  • @Yooric 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) – DreamTeK Feb 18 '22 at 14:05
  • @DreamTeK 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? – Yooric Feb 21 '22 at 09:18
  • 1
    @Yooric 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. – DreamTeK Feb 21 '22 at 10:19
  • Created a qustion: https://stackoverflow.com/questions/71206689/auto-resize-not-wokring-on-textareas-on-different-tabs @DreamTeK Thanks for taking your so far time. – Yooric Feb 21 '22 at 12:56
  • Instead of using "auto" for the initial height, you can also use 0. – Aetinx Jun 29 '22 at 20:50
  • @ZorroDeLaArena 's suggestion should be incorporated into the answer. Without it, the solution is essentially broken for line sizes of 1. – Mud Aug 25 '22 at 17:07
  • @Mud Doesn't the PRESET TEXTAREA HEIGHT option accomodate for this requirement? – DreamTeK Aug 26 '22 at 08:03
  • 1
    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. – Mud Aug 26 '22 at 16:15
  • @Mud OK thanks. I have tested the findings and ammended the answer to accomodate. – DreamTeK Aug 30 '22 at 10:09
  • @DreamTeK, can you help me with this question, I try to convert your answer to ReactJS https://stackoverflow.com/questions/73916949/ref-doesnt-get-the-right-scrollheight – UMR Oct 01 '22 at 08:41
  • You capture onInput here, but not the form's onReset event. So textareas won't resize if you reset the form they're in! – Doin Nov 17 '22 at 11:29
  • I would also change the .on("input") to .on("focus") so that it resizes as soon as you put your cursor in the input. – Vincent Feb 23 '23 at 23:11
  • @Vincent, but the size won't change until the content is edited. – DreamTeK Feb 24 '23 at 09:19
  • you should stop resizing the box if the user manually resizes it – Boris Verkhovskiy Jun 07 '23 at 15:58
  • @BorisVerkhovskiy that's a good idea, but I think it would need to be optional. – DreamTeK Jun 08 '23 at 07:47
274

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.

Community
  • 1
  • 1
panzi
  • 7,517
  • 5
  • 42
  • 54
  • 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! – Chris Moschini May 10 '11 at 06:14
  • 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. – panzi May 10 '11 at 18:42
  • 13
    It does! Made a jsfiddle for ya: http://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: http://jsfiddle.net/CbqFv/2/ It solves the IE issue but Firefox stops working. – Chris Moschini May 10 '11 at 18:58
  • 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. – Helen Neely Feb 18 '12 at 08:45
  • 3
    @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. – panzi Feb 23 '12 at 04:28
  • 1
    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. – Denilson Sá Maia Sep 20 '12 at 18:40
  • 3
    @DenilsonSá If one could only assume that only modern browsers are used the web would be a better place. – panzi Sep 22 '12 at 01:52
  • Does this work if I have multiple textboxes that require the feature? – user3388884 Mar 26 '14 at 20:39
  • 2
    This won't work well if a scrollbar is envolved in IE11. If you use this fiddle http://jsfiddle.net/CbqFv/ and enter lines until you've got a scrollbar you will see it. Any ideas? – kaljak Aug 25 '15 at 13:05
  • kaljak, does adding `overflow: hidden;` help? Edit: Wait, that is already there. Then no idea. – panzi Aug 25 '15 at 14:37
  • What can I do for prevent scroll bar flashing? If the style `overflow:auto;` – ollazarev Apr 08 '16 at 23:12
  • @ollazarev 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). – panzi Apr 09 '16 at 19:02
  • 12
    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. – rr- Jun 12 '16 at 09:03
  • would it hang the browser if pasted large text inside like 3MB file after uploading and getting the response back into the textarea – Muhammad Omer Aslam Sep 11 '19 at 10:28
  • On Firefox 70 it doesn't resize on first character that overflows. On second char it gets resized. – cdalxndr Dec 02 '19 at 21:15
  • 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? – Vladyn May 28 '20 at 07:54
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/

Ted
  • 580
  • 4
  • 22
chim
  • 8,407
  • 3
  • 52
  • 60
  • 5
    This is good, but I would add `overflow-y: hidden;` to the css to prevent the scroll bar from briefly flashing when resize occurs. – brettjonesdev May 06 '13 at 15:11
  • 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. – chim Jun 21 '13 at 09:31
  • I like this solution a lot, in the first example, how could I limit the amount of rows and get rid of the padding? – Darius Sep 21 '13 at 07:12
  • 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. – chim Sep 23 '13 at 10:02
  • @Darius 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. – chim Sep 23 '13 at 10:18
  • 1
    Use multiple events to make work for wide verity of scenario `$('textarea.auto-resize').on('change cut paste drop keyup', function(){...})` – raxith May 04 '14 at 11:43
  • 2
    Jumps around like crazy in Chrome 40 Win 8.1 on texts longer than the viewport. Renders it quite unusable. – tobibeer Feb 11 '15 at 13:59
  • 1
    Holding enter (newline) results in scrolling. The size does not adjust until the key is released. – Niels Abildgaard Apr 23 '15 at 17:03
32
<!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>

Edit: modernized code. Changed onkeyup attribute to addEventListener.
Edit: keydown works better than keyup
Edit: declare function before using
Edit: input works better than keydown (thnx @WASD42 & @MA-Maddin)

jsfiddle

GijsjanB
  • 9,944
  • 4
  • 23
  • 27
  • 3
    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. – WASD42 Sep 24 '13 at 14:10
  • So just use the `input` event instead. See http://stackoverflow.com/a/14029861/1951524 – Martin Schneider Nov 22 '16 at 20:52
  • 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'; }); });` – Meisner Jan 29 '17 at 01:01
  • 1
    @Meisner 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. – GijsjanB Mar 09 '17 at 09:52
  • 2
    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. – AIon Feb 12 '19 at 19:53
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.

vatavale
  • 1,470
  • 22
  • 31
  • 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? – user2513846 Mar 22 '16 at 06:07
  • 1
    @user2513846 Looks like it's not possible by the design of multi line editing. I made an example of animating textarea size: https://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. – vatavale Mar 23 '16 at 11:32
  • 1
    @user2513846 However, with one more empty line at the end of textarea, it's possible to have smooth animation: https://jsfiddle.net/p23erdfr/ – vatavale Mar 23 '16 at 12:15
  • 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;} – Gregor Simončič Oct 03 '20 at 17:21
  • @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. – vatavale Oct 04 '20 at 14:22
29

Found an one liner from here;

<textarea name="text" oninput="this.style.height = ''; this.style.height = this.scrollHeight +'px'"></textarea>
Kerem
  • 11,377
  • 5
  • 59
  • 58
17K
  • 321
  • 3
  • 4
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.

Max Hoffmann
  • 2,957
  • 1
  • 17
  • 13
  • 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. – Ajax Feb 09 '16 at 14:27
17

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.

bobince
  • 528,062
  • 107
  • 651
  • 834
  • 1
    Which browsers are supposed to have problems with `scrollHeight` for textareas? Works fine with current versions of IE, Firefox and Opera... – Christoph Jan 18 '09 at 09:54
  • 1
    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. – bobince Jan 18 '09 at 12:38
14

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

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
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.

Racil Hilan
  • 24,690
  • 13
  • 50
  • 55
  • There is already an answer using contenteditable on this page: https://stackoverflow.com/questions/454202/creating-a-textarea-with-auto-resize/26413009#26413009 – adabru Aug 06 '18 at 08:42
  • @adabru 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. – Racil Hilan Aug 10 '18 at 06:59
7

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.

Karolis Juodelė
  • 3,708
  • 1
  • 19
  • 32
  • 1
    "_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. – Jamie Barker Jan 20 '16 at 15:39
  • Simple best solution I've seen and tried to come up with for reactive update. Thanks! – Alex Shink Nov 23 '20 at 18:52
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>
G-Cyrillus
  • 101,410
  • 14
  • 105
  • 129
Webmaster G
  • 502
  • 5
  • 12
  • Chrome will add
    elements on ENTER.
    – sbaechler Nov 04 '16 at 18:36
  • `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`. – mik01aj Dec 12 '17 at 11:02
  • @_sbaechler: the
    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.
    – adabru Aug 06 '18 at 08:46
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.

Joseph Nields
  • 5,527
  • 2
  • 32
  • 48
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>
G-Cyrillus
  • 101,410
  • 14
  • 105
  • 129
Nikunj Bhatt
  • 188
  • 4
  • 16
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

h0mayun
  • 3,466
  • 31
  • 40
  • 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. – Yeti Aug 10 '17 at 11:08
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>
chrmcpn
  • 574
  • 6
  • 10
  • 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. – Karol Websky Dec 12 '17 at 13:23
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;
  });
artnik-pro
  • 49
  • 2
4

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} />;
Ricardo Canelas
  • 2,280
  • 26
  • 21
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>
  • jQuery's `.live()` has been deprecated. http://api.jquery.com/live/ You'll generally want to use `.on()` instead. – Luke Jun 27 '14 at 22:22
3

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);
hasen
  • 161,647
  • 65
  • 194
  • 231
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

Eric Platon
  • 9,819
  • 6
  • 41
  • 48
revive
  • 831
  • 2
  • 15
  • 31
3

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>
Mauricio Sánchez
  • 4,602
  • 1
  • 23
  • 15
  • Cleanest solution. but as we should stop using jQuery: textarea.addEventListener('keyup', () => { textarea.style.height = 0; textarea.style.height = `${textarea.scrollHeight}px`; }); – Toni Michel Caubet Feb 06 '19 at 10:30
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';
    }
  }
Divyanshu Rawat
  • 4,421
  • 2
  • 37
  • 53
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)

localhostdotdev
  • 1,795
  • 16
  • 21
  • 3
    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. – Nathalia Xavier Jul 24 '19 at 09:05
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.

Samuel Gfeller
  • 840
  • 9
  • 19
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

Kurenai Kunai
  • 1,842
  • 2
  • 12
  • 22
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)
}
trh
  • 7,186
  • 2
  • 29
  • 41
orange01
  • 1,584
  • 1
  • 16
  • 28
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();
karoluS
  • 2,980
  • 2
  • 23
  • 44
Kim Homann
  • 3,042
  • 1
  • 17
  • 20
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();
}
Igor Krupitsky
  • 787
  • 6
  • 9
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);
    });
karthik_krish
  • 93
  • 1
  • 7
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>
Chris
  • 2,174
  • 28
  • 37
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';
}
rrr
  • 35
  • 1
  • 4
    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. – Eastern Monk Mar 13 '12 at 17:44
  • @EasternMonk if you try it it actually works well and is quite intuitive IMHO: https://jsbin.com/tilokafasa/1/edit?html,js,output – localhostdotdev May 09 '19 at 15:57
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

gunnerz
  • 1,898
  • 5
  • 24
  • 39
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.

18C
  • 2,014
  • 10
  • 16
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.

Karl Zillner
  • 581
  • 7
  • 16
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>
bafsar
  • 1,080
  • 2
  • 16
  • 16
  • 1
    Full Jquery : `$(function() { $("textarea.auto-grow").on("input", function() { $(this).css("height","5px").css("height",$(this).prop("scrollHeight")+"px") }); })` – Mystral Feb 10 '23 at 10:03
  • @Mystral, thanks. It's more like jquery. I added also your code too. – bafsar Feb 15 '23 at 12:15
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;
}
Johansrk
  • 5,160
  • 3
  • 38
  • 37
0

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>
hossein sedighian
  • 1,711
  • 1
  • 13
  • 16
0

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>
erfanilaghi
  • 206
  • 3
  • 12
  • and if you want to use it with a form that html itself submit it you can use a hidden `input` or` textarea` and `` as your submit button. – erfanilaghi Aug 27 '23 at 04:34
-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.

Matthew
  • 199
  • 1
  • 3
  • 12
-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);
}
-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();
Darex1991
  • 855
  • 1
  • 10
  • 24
-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,

Goon Nguyen
  • 1,462
  • 11
  • 26
-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.

patrick
  • 11,519
  • 8
  • 71
  • 80
  • 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' ); – patrick Jul 02 '16 at 15:39
  • Don't know why this is downvoted. It's a working solution which we still use today, 7 years after we uploaded it – patrick Jun 07 '23 at 12:46
-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;
  }

}
André
  • 12,497
  • 6
  • 42
  • 44
-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');
});
Algorithm
  • 329
  • 6
  • 16
-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;
snnsnn
  • 10,486
  • 4
  • 39
  • 44