SVG object display toggle stops EventListener - javascript

I managed to load an external svg and to grab the path's name and insert it into a tooltip.
But when i now toggle the display of the div, containing the svg object, off and on again the EventListener somehow doesn't work anymore (it only works in FireFox) and the name of the path will not show again.
Any idea Why Safari and Chrome won't listen anymore?
window.onload = function() {
var a = document.getElementById("Map1");
var svgDoc = a.contentDocument;
var myImage = svgDoc.getElementsByTagName("path");
for (var i = 0; i < myImage.length; i++) {
myImage[i].addEventListener('mouseover', show);
myImage[i].addEventListener('mouseout', hide);
}
var text = document.getElementById("show");
function show() {
var myID = this.id;
text.innerHTML = myID;
document.getElementById("show").style.display = "block";
}
function hide() {
var myID = this.id;
text.innerHTML = '';
document.getElementById("show").style.display = "none";
}
}
function myFunction() {
var toggle = document.getElementById("Map");
toggle.style.display = toggle.style.display === 'none' ? 'block' : 'none';
}
#show {
display: none;
}
<button onclick="myFunction()">Show Map!</button>
<div id="show" style="position: absolute; left: 100px; background-color:aqua; padding: 5px;"></div>
<div id="Map" style="display: block;"><object id='Map1' data="Test-01.svg" type="image/svg+xml">Your browser doesn't support SVG</object></div>

That's a weird bug, which I did reproduce here.
The core of this bug is that webkit browsers will unload an <object> or <embed> content when its CSS display is set to none. Doing so, it will remove all of its content, your event listeners included.
Thus, you've got two possible workarounds (at least) :
1 - Use an <iframe>. This tag is not concerned by this bug...
Live example
2 - Use some other CSS rules to hide your <object>.
Something like the following should provide the same functionality as display: none
object.hidden {
position: absolute;
z-index: -99;
width: 0px;
height: 0px;
visibility: hidden;
pointer-events: none;
}
Live example
And to add more weirdness, this bug doesn't affect BlobURIs in chrome (couldn't test in Safari, the blob gets downloaded, one other bug...).

Related

Add a style to html and body via onclick

I am having a problem with my hamburger menu, my background page scrolling when it is open. I noticed that if I add 'overflow: hidden' to the body and html, it fixes the problem. However, when I close the menu, the body is obviously still locked. How can I add javascript to cancel these styles from the body and html?
This is what I have tried:
<div class="navbar_toggle" onclick="nonscroll(this)">
<script>
function nonscroll(elem) {
document.body.style.overflow = "hidden";
document.html.style.overflow = "hidden";
}
</script>
When I click the button, I want these styles to apply. When I close the menu, I want them to disappear. Is there a very simple way to fix this?
Solution
Copy from this example, paste into your page:
function FixScrollToggle (node) {
var target = document.body;
function isClicked () {
return target.classList.contains('fixScrollToggle--on');
}
function freeze() {
target.classList.add('fixScrollToggle--on');
}
function unFreeze() {
target.classList.remove('fixScrollToggle--on');
}
function onClick (e) {
if (isClicked()) { return unFreeze(); }
return freeze();
}
node.addEventListener('click', onClick, false);
}
document.addEventListener('DOMContentLoaded', function () {
Array.prototype.slice.
call(document.querySelectorAll('[data-apply-fix]')).
forEach(FixScrollToggle);
});
.fixScrollToggle--on {
overflow: hidden;
background-color: #c00;
}
<div class="navbar_toggle" data-apply-fix>Click me</div>
It's not the most easy way, but it's a clean and relatively easy way. Just put the JS code into a <script> tag in your page.
Explanation
This code works by adding a click eventlistener to each HTML element which has a data-apply-fix attribute set. This way, you can attach the same behaviour to multiple elements on your page.
The behaviour of manipulating the CSS is entirely done with the CSS class fixScrollToggle--on. This way, you have a very clean separation of concerns.
In nonscroll() function, you need to do two things:
Check if nav is hidden or shown.
When you know the nav visibility, you can update style for body and html.
<div class="navbar_toggle" onclick="nonscroll(this)">
<script>
function nonscroll(elem) {
// check if navbar is hidden or shown
// if nav is hidden: "body overflow is 'hidden'"
// else "body overflow is 'static'"
var nav = document.getElementsByClassName("navbar_toggle");
var nav_hidden = (window.getComputedStyle(nav[0]).visibility === "hidden")
if(nav_hidden) {
document.body.style.overflow = "hidden";
document.html.style.overflow = "hidden";
} else {
document.body.style.overflow = "static";
document.html.style.overflow = "static";
}
}
</script>
Simple ways to do that is using toggle class on click listener, as your code above it could:
var toggle = document.getElementsByClassName('navbar_toggle')[0];
var html = document.getElementsByTagName('html')[0];
var body = document.getElementsByTagName('body')[0];
var all = [html,body];
toggle.addEventListener( 'click', function() {
for ( var i=0; i < all.length; i++ ) {
all[i]classList.toggle('is-active');
}
});
Then ur css should be:
html, body {
overflow: auto;
}
.is-active {
overflow: hidden;
position: fixed; // prevent body scrolling for safari and ios
}

Javascript transition duration won't work

I wan't to make show() and hide() method like jquery have, but with pure javascript because I want to modify how the element show and hide. But after my attempts, I've changed where the code placed, changed the code, etc, still it won't work. Only for a few times it was work but it was inconsistent (when I try to run it through firefox, it work for once but never again). The display (block and none) and the exact width and height is work, but not the 2s transition. How to fix this?
<!doctype html>
<html>
<head>
<style>
div {
width: 0px;
height: 0px;
background-color: yellow;
border: 1px solid black;
display: none;
}
</style>
</head>
<body>
<div>
</div>
<button>
click !
</button>
<script>
var x = document.getElementsByTagName("button");
var y = document.getElementsByTagName("div");
x[0].onclick = fungsi;
function fungsi() {
if (y[0].style.display != "block") {
y[0].style.display = "block";
y[0].style.transition = "width 2s";
y[0].style.transition = "height 2s";
y[0].style.width = "100px";
y[0].style.height = "100px";
} else {
y[0].style.display = "";
y[0].style.transition = "width 2s";
y[0].style.transition = "height 2s";
y[0].style.width = "";
y[0].style.height = "";
}
};
</script>
</body>
</html>
I've messed around with your code and found that the reason for your problem was the switching from display: none; to display: block; and back. I've made a simple solution for this if you would like to use it.
Here is the modified CSS code.
div {
width: 0px;
height: 0px;
background-color: yellow;
border: none;
}
Here is the modified JS code.
var x = document.getElementsByTagName("button");
var y = document.getElementsByTagName("div");
x[0].onclick = fungsi;
var expanded = false;
function fungsi() {
y[0].style.transition = "all 2s";
if (!expanded) {
y[0].style.border = "1px solid black";
y[0].style.width = "100px";
y[0].style.height = "100px";
expanded = true;
} else {
var applyBorder = function () {
y[0].style.border = "none";
};
y[0].style.width = "0";
y[0].style.height = "0";
expanded = false;
setTimeout(applyBorder, 2000);
}
};
And here is a JSFiddle of this code for an example.
It could be something to do with vendor prefixes
So as well as having the following:
y[0].style.transition
You will also need:
y[0].style.mozTransition
y[0].style.webkitTransition
Try that, hopefully should work.
What you are doing is not animating show and hide with "pure javascript", it really is animating show and hide with CSS3. You are just setting the CSS properties trough javascript!
That being said, CSS3 transitions are not supported by every browser. For example even IE9 does not support it. Some other browser only work with prefixed versions of this property.
Try setting -moz-transition, -webkit-transition and -o-transition too.
For more details see: Transition browser support
However if you expect your animation to work across all major platforms I suggest you to use jQuery and try adjusting the settings to your desired behavior..
When you run
y[0].style.transition = "width 2s";
y[0].style.transition = "height 2s";
The first line will be overwritten by the second. So the transition goes only for width or height at a time, and when one of them is 0, the transition will be invisible.
You should set transition like this:
y[0].style.transition = 'width 2s,height 2s';
Or just set it for all properties that support transition:
y[0].style.transition = 'all 2s';
BTW, since the transition property is not changing, you should set them outside the changing part.
Another problem is, the <div> must be visible before the animation starts, otherwise it will have the desired width and height once become visible, and no transition is needed any more. visibility is another choice since an element with visibility: hidden still takes the place.
Here is a working copy of code:
<!doctype html>
<html>
<head>
<style>
div {
width: 0px;
height: 0px;
background-color: yellow;
border: 1px solid black;
/* Use visibility instead of display */
visibility: hidden;
}
</style>
</head>
<body>
<div>
</div>
<button>
click !
</button>
<script>
var x = document.getElementsByTagName("button");
var y = document.getElementsByTagName("div");
x[0].onclick = fungsi;
// set transition
y[0].style.transition = "width 2s,height 2s";
function fungsi() {
if (y[0].style.visibility != "visible") {
y[0].style.visibility = "visible";
y[0].style.width = "100px";
y[0].style.height = "100px";
} else {
y[0].style.visibility = "";
y[0].style.width = "";
y[0].style.height = "";
}
};
</script>
</body>
</html>
And something more, if you want to hide the element after the animation ends, setTimeout will work.

Cannot update div style attributes

I'm trying to change a couple of style attributes. Here is the style I first assigned to clickedMenuHexagonDiv:
clickedMenuHexagonDiv.style.MozTransform = "scale(.9999)";
clickedMenuHexagonDiv.style.width = num2px(this.width);
clickedMenuHexagonDiv.style.marginRight = "3px";
clickedMenuHexagonDiv.style.position = "relative";
clickedMenuHexagonDiv.style.zIndex = "5";
clickedMenuHexagonDiv.style.styleFloat = "right";
clickedMenuHexagonDiv.style.cssFloat = "right";
Here is the code later on, for the attributes I want to change:
clickedMenuHexagonDiv.className = "centerHexagonDiv";
clickedMenuHexagonDiv.style.bottom = "auto";
clickedMenuHexagonDiv.style.right = "auto";
clickedMenuHexagonDiv.style.float = "none";
alert("clickedMenuHexagonDiv: " + clickedMenuHexagonDiv.style.cssText);
And here is the output of the alert:
clickedMenuHexagonDiv: transform: scale(0.9999); width: 80px; margin-right: 3px; position: relative; z-index: 5; float: right; right: auto; bottom: auto;
As you can see, it only updates attributes that weren't declared earlier. There were no console errors. Also, somewhat oddly, bottom and right were changed by the jquery animate function (I put an alert in before clickedMenuHexagonDiv.className = "centerHexagonDiv";, and it showed values other than "auto" for bottom and right.
I figured out that I can sort of fix this if I insert clickedMenuHexagonDiv.style.cssText = "" before changing the style attributes, but then I have to declare all of the attributes again. I'd rather try to understand why I can't update specific attributes.
If figured it out: I needed to use "styleFloat" and/or "cssFloat". "float" isn't a css property.
Here's the updated code (only the second section needed updating):
clickedMenuHexagonDiv.className = "centerHexagonDiv";
clickedMenuHexagonDiv.style.bottom = "auto";
clickedMenuHexagonDiv.style.right = "auto";
clickedMenuHexagonDiv.style.styleFloat = "none";
clickedMenuHexagonDiv.style.cssFloat = "none";

textarea not shrinking when deleting character [duplicate]

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 )
};
}
A COMPLETE YET SIMPLE SOLUTION
Updated 2022-08-30
(Added support for single row multiple textbox by default)
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 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 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>
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.
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/
<!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
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.
Found an one liner from here;
<textarea name="text" oninput="this.style.height = ''; this.style.height = this.scrollHeight +'px'"></textarea>
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.
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.
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
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.
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.
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>
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:
Window resize events, if the width of the textarea changes with window resizing, or other events that change the width of the textarea
When the textarea's display style attribute changes, e.g. when it goes from none (hidden) to block
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.
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>
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;
});
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
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>
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>
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);
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
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>
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';
}
}
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)
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
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)
}
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();
}
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();
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);
});
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>
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} />;

Creating a textarea with auto-resize

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 )
};
}
A COMPLETE YET SIMPLE SOLUTION
Updated 2022-08-30
(Added support for single row multiple textbox by default)
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 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 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>
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.
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/
<!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
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.
Found an one liner from here;
<textarea name="text" oninput="this.style.height = ''; this.style.height = this.scrollHeight +'px'"></textarea>
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.
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.
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
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.
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.
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>
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:
Window resize events, if the width of the textarea changes with window resizing, or other events that change the width of the textarea
When the textarea's display style attribute changes, e.g. when it goes from none (hidden) to block
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.
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>
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;
});
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
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>
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>
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);
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
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>
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';
}
}
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)
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
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)
}
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();
}
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();
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);
});
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>
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} />;

Categories