Creating a textarea with auto-resize
A COMPLETE YET SIMPLE SOLUTION
Updated 2020-05-14(Improved browser support for mobiles and tablets)
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-67 tested).
- With Chrome (v37-74 tested).
- With IE (v9-v11 tested).
- With Edge (v14-v18 tested).
- With IOS Safari.
- With Android Browser.
- With JavaScript strict mode.
- Is w3c validated.
- And is streamlined and efficient.
OPTION 1 (With jQuery)
This option requires jQuery and has been tested and is working with 1.7.2 - 3.6
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 = "auto"; this.style.height = (this.scrollHeight) + "px";});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.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>
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>
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": "auto", "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 code to invoke the function in option 1.
$("textarea").trigger("input");
PRESET TEXTAREA HEIGHT
To fix the initial height of the textarea you will need to add an additional 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>
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 jsfiddleIt 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 textarea
s (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.
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/