244

I want to make height of textarea equal to height of the text within it (And remove the scroll bar)

HTML

<textarea id="note">SOME TEXT</textarea>

CSS

textarea#note {
    width:100%;
    direction:rtl;
    display:block;
    max-width:100%;
    line-height:1.5;
    padding:15px 15px 30px;
    border-radius:3px;
    border:1px solid #F7E98D;
    font:13px Tahoma, cursive;
    transition:box-shadow 0.5s ease;
    box-shadow:0 4px 6px rgba(0,0,0,0.1);
    font-smoothing:subpixel-antialiased;
    background:linear-gradient(#F9EFAF, #F7E98D);
    background:-o-linear-gradient(#F9EFAF, #F7E98D);
    background:-ms-linear-gradient(#F9EFAF, #F7E98D);
    background:-moz-linear-gradient(#F9EFAF, #F7E98D);
    background:-webkit-linear-gradient(#F9EFAF, #F7E98D);
}

JsFiddle: http://jsfiddle.net/Tw9Rj/

Moussawi7
  • 12,359
  • 5
  • 37
  • 50
Mohammad Mahdi Naderi
  • 2,975
  • 2
  • 14
  • 9

8 Answers8

547

This using Pure JavaScript Code.

function auto_grow(element) {
  element.style.height = "5px";
  element.style.height = (element.scrollHeight) + "px";
}
textarea {
  resize: none;
  overflow: hidden;
  min-height: 50px;
  max-height: 100px;
}
<textarea oninput="auto_grow(this)"></textarea>
Penny Liu
  • 15,447
  • 5
  • 79
  • 98
Moussawi7
  • 12,359
  • 5
  • 37
  • 50
  • 12
    If you add some additional height it will stop the text from scrolling for the split second before the element is resized. `(element.scrollHeight+20)+"px";` – Nicholas Sep 21 '15 at 06:40
  • 9
    works nice but has initial "jump". adding: if (element.scrollHeight > 80) { element.style.height = 5 + "px"; element.style.height = (element.scrollHeight + 10) + "px"; } helped. (min-height: 80px) – Michael Brennt Nov 02 '15 at 15:20
  • 13
    may I suggest to use oninput? and height = auto instead of 5px? – CoderPi Dec 14 '15 at 20:30
  • 3
    FWIW I tried height=auto in a control and found that the textarea wouldn't shrink back to 1 line (in Chrome) - the smallest it would go is 2 lines, even if there was one line (or no) text. height=5px is making the textarea shrink correctly in my implementation. – Stefan Mohr Jun 17 '16 at 21:06
  • 3
    @StefanMohr To fix this, set the textarea's `rows` attribute to 1. – Graham Sep 20 '16 at 14:11
  • 11
    Simple Inline JS solution `` – jackkorbin Jun 26 '17 at 07:22
  • I found useful to call `auto_grow()` on `keydown` using `setImmediate(auto_grow, my_elem)` to avoid delay. – Ivan Perevezentsev May 01 '18 at 14:09
  • 5
    Doesn't work when text is modified (selected, cut, or pasted) using the mouse or right click menu. Use the `input` event instead of `keyup` event. – Dave F May 31 '18 at 05:14
  • If the height is 5px, even very briefly, the bottom of the webpage comes up and moves the viewport, then it moves again when the height is corrected. Try putting lots of content into that textarea and typing new lines into it to see what I mean. – Costa Michailidis Oct 26 '18 at 19:59
  • Does not work if text overflows horizontally – jjxtra May 03 '19 at 18:01
  • It appears that having the event fired also onkeydown can covers the scenario when users hold the delete key to delete content (or less likely, holding a normal key to type the same character) – malnosna Aug 06 '19 at 20:05
  • 1
    I think correct calculating of optimal textarea height is `var scrollHeight = Math.max(this.scrollHeight, this.offsetHeight, this.clientHeight)` Because calculating these params in Chrome/Safari and Opera different. So safety way is take Max of them ) – mrkiril Mar 30 '20 at 16:23
  • Guys I implemented this code and it works great especially after changing the event to `input` since the user may copy paste text as well. But on emptying the div after submit, the div doesn't come back to its original size. I have posted my question here. Please take a look https://stackoverflow.com/questions/61632585/how-to-remove-or-modify-dynamically-added-inline-css – Souvik Ray May 06 '20 at 10:22
  • 2
    Temporarily set the minHeight of the parent to prevent the page jumping around: ```element.parentNode.style.minHeight = element.parentNode.clientHeight + "px"; element.style.height = "5px"; element.style.height = (element.scrollHeight)+"px"; element.parentNode.style.minHeight = 0;``` – Simon Sep 22 '20 at 17:34
  • This solution worked for me if I set style="resize: none; overflow: hidden; height: 100%;" – Skyfish Dec 02 '22 at 10:53
  • This has a bug. When deleting content from the textarea, the height does not shrink. – John Miller Apr 11 '23 at 16:25
  • @Nicholas. An additional advantage for the user of adding a bottom blank area of at least a line height in a textarea is that it indicates that more content can be added, whereas making the control just fit the existing text doesn't. That it continues to expand with the extra space as more text is added further reinforces this – Patanjali May 19 '23 at 04:02
119

For those of us accomplishing this with Angular JS, I used a directive

HTML:

<textarea elastic ng-model="someProperty"></textarea>

JS:

.directive('elastic', [
    '$timeout',
    function($timeout) {
        return {
            restrict: 'A',
            link: function($scope, element) {
                $scope.initialHeight = $scope.initialHeight || element[0].style.height;
                var resize = function() {
                    element[0].style.height = $scope.initialHeight;
                    element[0].style.height = "" + element[0].scrollHeight + "px";
                };
                element.on("input change", resize);
                $timeout(resize, 0);
            }
        };
    }
]);

$timeout queues an event that will fire after the DOM loads, which is what's necessary to get the right scrollHeight (otherwise you'll get undefined)

Gaurav
  • 3,614
  • 3
  • 30
  • 51
blockloop
  • 5,565
  • 5
  • 30
  • 31
  • 1
    Sweet, thanks for posting! Just wanted to add that I was having an issue where removing lines of text wouldn't decrease the height enough (2px at a time, possibly related to using bootstrap). I fixed this by setting element[0].style.height in the resize function to 1px first, then setting it to the scrollHeight. – Kevin Lawrence Aug 24 '14 at 22:55
  • 1
    It didn't shrink for me. I added a couple lines so it shrinks until its default/initial height. `link: function($scope, element) {` `$scope.initialHeight = $scope.initialHeight || element[0].style.height;` `var resize = function() {` `element[0].style.height = $scope.initialHeight;` `element[0].style.height = "" + element[0].scrollHeight + "px";` `};` `element.on("blur keyup change", resize);` `$timeout(resize, 0);` `}` – htrufan Jan 06 '15 at 17:08
  • 1
    This is great. I also needed resize when the model changes (my comments box is dynamic). So I added: $scope.$watch(attrs.ngModel, resize); – What-About-Bob Aug 12 '15 at 15:07
  • @Bob `element.on("blur keyup change", resize)` should cover model changes. – blockloop Aug 12 '15 at 19:41
  • It's better to use [`element.on('input change')`](http://stackoverflow.com/a/11338644/320036) - otherwise `resize` is only called after a render and it will flicker. – z0r Aug 14 '15 at 01:50
  • Good call @z0r I'll update the answer – blockloop Aug 15 '15 at 02:33
  • Excellent solution @blockloop – Blaze Jan 25 '16 at 12:23
  • It's quite old, but I'll give it a try. I'm using this but the scrollHeight is always 0 while the value of the textarea is set when i look at it during debugging. Any ideas? – kopi_b Oct 07 '16 at 14:12
  • 1
    Experiencing the same thing as @kopi_b -- scrollHeight is 0. Seems this is happening when it's contained within an ancestor element that is shown/hidden via ngShow. – Nuri Hodges Oct 27 '16 at 20:46
  • Thanks for the angular directive approach. This got me pointed to using the ng-elastic package on npm for Angular 2+: https://www.npmjs.com/package/ng-elastic –  Jul 29 '17 at 20:33
  • if(element[0].scrollHeight > 0) element[0].style.height = "" + element[0].scrollHeight + "px"; – Makatun Feb 22 '18 at 23:58
  • @NuriHodges @kopi_b you can use this `$watch` here to fix the scroll height 0 problem for `display:none` elements. https://stackoverflow.com/questions/19048985/angularjs-better-way-to-watch-for-height-change – a2f0 Jul 12 '19 at 02:59
  • Does anyone have AngularX solution? – Brackets Dec 26 '20 at 14:04
64

It can be achieved using JS. Here is a 'one-line' solution using elastic.js:

$('#note').elastic();

Updated: Seems like elastic.js is not there anymore, but if you are looking for an external library, I can recommend autosize.js by Jack Moore. This is the working example:

autosize(document.getElementById("note"));
textarea#note {
 width:100%;
 box-sizing:border-box;
 direction:rtl;
 display:block;
 max-width:100%;
 line-height:1.5;
 padding:15px 15px 30px;
 border-radius:3px;
 border:1px solid #F7E98D;
 font:13px Tahoma, cursive;
 transition:box-shadow 0.5s ease;
 box-shadow:0 4px 6px rgba(0,0,0,0.1);
 font-smoothing:subpixel-antialiased;
 background:linear-gradient(#F9EFAF, #F7E98D);
 background:-o-linear-gradient(#F9EFAF, #F7E98D);
 background:-ms-linear-gradient(#F9EFAF, #F7E98D);
 background:-moz-linear-gradient(#F9EFAF, #F7E98D);
 background:-webkit-linear-gradient(#F9EFAF, #F7E98D);
}
<script src="https://rawgit.com/jackmoore/autosize/master/dist/autosize.min.js"></script>
<textarea id="note">Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.</textarea>

Check this similar topics too:

Autosizing textarea using Prototype

Textarea to resize based on content length

Creating a textarea with auto-resize

Community
  • 1
  • 1
Mike
  • 1,979
  • 2
  • 16
  • 29
  • 226
    I want to do it with css. – Mohammad Mahdi Naderi Jul 21 '13 at 12:28
  • 1
    I'm not sure it's possible with CSS. – Mike Jul 21 '13 at 12:49
  • gave this a shot since it was the accepted answer but when i started typing in my textarea it froze my browser for a few seconds then spit out everything i had typed at once. ended up rolling my own based on @brettof86 answer. – Rush Frisby Jul 21 '15 at 15:03
  • 1
    For future peeps: I think brettof86 changed their username to blockloop, so the answer being referred to is the angular one below: – MalcolmOcean Oct 24 '15 at 00:41
  • elasticjs is a nice thing, I just added a class 'elastic' to the textareas of my target and then $('textarea.elastic').elastic() – MinhajulAnwar Jun 02 '16 at 05:51
  • elastic js demo doesn't work for me: firefox 47, chrome 51. – Edward Newell Jun 16 '16 at 10:42
  • 3
    The link of elastic js is broken... – mesqueeb Jul 16 '16 at 02:57
  • 11
    Instead of referring to just a library, a better answer would have been one without the requirement of any external libraries. This answer probably hasn't helped anyone in some time. – Jayant Bhawal Jul 29 '16 at 09:37
  • @JayantBhawal I agree. It's a disgrace that an answer on this site can be "use a third party library". That's not an answer, a cursory google search could have told me that. I don't want a third party library. – echolocation Nov 01 '16 at 20:30
  • 16
    Thank you for criticizing me guys, but the decision to accept it as the answer wasn't mine, and I won't mind if it's going to be someone's else approach accepted. I just did my best and suggested a ready-to-use solution. Since it's not possible to achieve this via CSS, at the end of the day you will end up using JS most likely, so why not to consider to use the one that already has been written. And yes, you can google for it, but I did this job for you. – Mike May 09 '17 at 19:54
15

I used jQuery AutoSize. When I tried using Elastic it frequently gave me bogus heights (really tall textarea's). jQuery AutoSize has worked well and hasn't had this issue.

Peter
  • 9,643
  • 6
  • 61
  • 108
13

I see that this is answered already, but I believe I have a simple jQuery solution ( jQuery is not even really needed; I just enjoy using it ):

I suggest counting the line breaks in the textarea text and setting the rows attribute of the textarea accordingly.

var text = jQuery('#your_textarea').val(),
    // look for any "\n" occurences
    matches = text.match(/\n/g),
    breaks = matches ? matches.length : 2;

jQuery('#your_textarea').attr('rows',breaks + 2);
Ikhlak S.
  • 8,578
  • 10
  • 57
  • 77
Douglas.Sesar
  • 4,214
  • 3
  • 29
  • 36
  • 1
    That's pretty slick. This seems to work nicely: textarea.on('input propertychange keyup change', function(){ this.rows = this.value.match(/\n/g).length + 1 }) – Dan Mar 12 '14 at 22:19
  • 1
    Good solution. Note that it doesn't apply to those who use `display:block`. – Adrien Mar 26 '14 at 20:28
  • 66
    Except it doesn't work if the text wraps. If the text wraps, the number of lines of text is not equivalent to the number of newline characters, since wrapping causes lines to break at white space between words. – Triynko Apr 22 '14 at 21:46
7

Jsfiddle

textarea#note {
    width:100%;
    direction:rtl;
    display:block;
    max-width:100%;
    line-height:1.5;
    padding:15px 15px 30px;
    border-radius:3px;
    border:1px solid #F7E98D;
    font:13px Tahoma, cursive;
    transition:box-shadow 0.5s ease;
    box-shadow:0 4px 6px rgba(0,0,0,0.1);
    font-smoothing:subpixel-antialiased;
    background:-o-linear-gradient(#F9EFAF, #F7E98D);
    background:-ms-linear-gradient(#F9EFAF, #F7E98D);
    background:-moz-linear-gradient(#F9EFAF, #F7E98D);
    background:-webkit-linear-gradient(#F9EFAF, #F7E98D);
    background:linear-gradient(#F9EFAF, #F7E98D);
    height:100%;
}
html{
    height:100%;
}
body{

   height:100%;    
}

or javascript

var s_height = document.getElementById('note').scrollHeight;
document.getElementById('note').setAttribute('style','height:'+s_height+'px');

Jsfiddle

Sebastian
  • 6,293
  • 6
  • 34
  • 47
Pumpkinpro
  • 837
  • 4
  • 5
3
var minRows = 5;
var maxRows = 26;
function ResizeTextarea(id) {
    var t = document.getElementById(id);
    if (t.scrollTop == 0)   t.scrollTop=1;
    while (t.scrollTop == 0) {
        if (t.rows > minRows)
                t.rows--; else
            break;
        t.scrollTop = 1;
        if (t.rows < maxRows)
                t.style.overflowY = "hidden";
        if (t.scrollTop > 0) {
            t.rows++;
            break;
        }
    }
    while(t.scrollTop > 0) {
        if (t.rows < maxRows) {
            t.rows++;
            if (t.scrollTop == 0) t.scrollTop=1;
        } else {
            t.style.overflowY = "auto";
            break;
        }
    }
}
user3530437
  • 89
  • 1
  • 3
-1

html

<textarea id="wmd-input" name="md-content"></textarea>

js

var textarea = $('#wmd-input'),
    top = textarea.scrollTop(),
    height = textarea.height();
    if(top > 0){
       textarea.css("height",top + height)
    }

css

#wmd-input{
    width: 100%;
    overflow: hidden;
    padding: 10px;
}
emitle
  • 323
  • 2
  • 4
  • 8