66

The current versions of Firefox and Chrome include a drag handler to resize a <textarea> box. I need to capture the resizing event, I thought it would be easy with jQuery's resize() event, but it doesn't work!

I have also tried the normal onResize event, but the result is the same. You can try it on JSFiddle.

Is there a way to capture it?

metrobalderas
  • 5,180
  • 7
  • 40
  • 47

11 Answers11

52

A standard way to handle element's resizing is the Resize Observer api, available in all modern web browser versions.

function outputsize() {
 width.value = textbox.offsetWidth
 height.value = textbox.offsetHeight
}
outputsize()

new ResizeObserver(outputsize).observe(textbox)
Width: <output id="width">0</output><br>
Height: <output id="height">0</output><br>
<textarea id="textbox">Resize me.</textarea>

If you need to deal with old versions of Chrome and Firefox (others untested), Mutation Observer can be used to detect the change of the style attribute.

function outputsize() {
 width.value = textbox.offsetWidth
 height.value = textbox.offsetHeight
}
outputsize()

new MutationObserver(outputsize).observe(textbox, {
 attributes: true, attributeFilter: [ "style" ]
})
Width: <output id="width">0</output><br>
Height: <output id="height">0</output><br>
<textarea id="textbox">Resize me.</textarea>

Resize Observer

Documentation: https://developer.mozilla.org/en-US/docs/Web/API/Resize_Observer_API

Spec: https://wicg.github.io/ResizeObserver

Current Support: http://caniuse.com/#feat=resizeobserver

Polyfills: https://github.com/pelotoncycle/resize-observer https://github.com/que-etc/resize-observer-polyfill https://github.com/juggle/resize-observer

Daniel Herr
  • 19,083
  • 6
  • 44
  • 61
  • 6
    Today, this would be the best solution, I think, as it is supported by most browsers. MutationObserver is such a powerful tool! This answer was an excellent example of how to use it. – NiklasMH Jul 10 '17 at 14:16
  • 5
    This solution should actually be pinned at the top. Simply, superb approach. I hate the other hacky ways mentioned in other answers and I definitely think using jQuery UI is an unnecessary overhead. – Fr0zenFyr Jan 16 '19 at 11:33
  • 1
    Resize Observer is the way to go, as it works on Chrome, FF and Safari. Mutation Observer doesn't work in Safari. – CpnCrunch Sep 17 '20 at 23:44
  • MutationObserver appears to have more browser support, including Safari: https://caniuse.com/mutationobserver – Raine Revere Jan 04 '21 at 19:15
  • @RaineRevere Resize observer has been supported in Safari since march: https://caniuse.com/?search=resize%20observer – Daniel Herr Jan 05 '21 at 02:51
  • Best answer out of all! Still in 2021 – Svenmarim May 25 '21 at 11:20
  • You should show that textarea is the element accessed by document.getElementById – Cybernetic Jun 17 '21 at 13:49
  • @Cybernetic document.getElementById is not used by that code – Daniel Herr Jun 19 '21 at 23:36
  • I thought I saw the error `textbox not defined` – Cybernetic Jun 19 '21 at 23:41
  • @Cybernetic What web browser are you using? – Daniel Herr Jun 20 '21 at 19:39
  • @DanielHerr Chrome. Works perfect when I use ‘document.getElementById(“my_textarea”)’. Are you saying other browsers will refer to the textarea by name alone? Never heard of JavaScript picking up elements that were not grabbed by ID or class. – Cybernetic Jun 20 '21 at 21:20
  • @Cybernetic Strange, works fine in Chrome for me. It's in the spec: https://html.spec.whatwg.org/multipage/window-object.html#named-access-on-the-window-object:window-4 – Daniel Herr Jun 22 '21 at 00:20
46

Chrome doesn't capture the resize event and that Chrome doesn't capture the mousedown, so you need to set the init state and then handle changes through mouseup:

jQuery(document).ready(function(){
   var $textareas = jQuery('textarea');

   // store init (default) state   
   $textareas.data('x', $textareas.outerWidth());
   $textareas.data('y', $textareas.outerHeight()); 

   $textareas.mouseup(function(){

      var $this = jQuery(this);

      if (  $this.outerWidth()  != $this.data('x') 
         || $this.outerHeight() != $this.data('y') )
      {
          // Resize Action Here
          alert( $this.outerWidth()  + ' - ' + $this.data('x') + '\n' 
               + $this.outerHeight() + ' - ' + $this.data('y')
               );
      }
  
      // store new height/width
      $this.data('x', $this.outerWidth());
      $this.data('y', $this.outerHeight()); 
   });

});

HTML

<textarea></textarea>
<textarea></textarea>

You can test on JSFiddle

Note:

  1. You could attach your own resizable as Hussein has done, but if you want the original one, you can use the above code
  2. As Bryan Downing mentions, this works when you mouseup while your mouse is on top of a textarea; however, there are instances where that might not happen like when a browser is not maximized and you continue to drag beyond the scope of the browser, or use resize:vertical to lock movement.

For something more advanced you'd need to add other listeners, possibly a queue and interval scanners; or to use mousemove, as I believe jQuery resizable does -- the question then becomes how much do you value performance vs polish?


Update: There's since been a change to Browsers' UI. Now double-clicking the corner may contract the textbox to its default size. So you also may need to capture changes before/after this event as well.

Dharman
  • 30,962
  • 25
  • 85
  • 135
vol7ron
  • 40,809
  • 21
  • 119
  • 172
  • 3
    In my quick testing, this only seems to work if you mouseup while your mouse is on top of a `textarea`. – Bryan Downing Jun 20 '14 at 00:28
  • 1
    @BryanDowning that's correct. The majority of the time, a user won't start changing the size of a text area and drag beyond the scope of the window/document before releasing; but that's not to say it can't/won't happen. For anything more advanced you'd need other listeners, and possibly a queue and interval scanners; or to use mousemove, as I believe jQuery resizable does – vol7ron Jun 20 '14 at 00:54
  • 2
    Right, just thought it deserved a mention :) This issue is most prevalent when using `resize: vertical` which only allows the `textarea` to grow in height. Very easy for the mouse to end up outside the `textarea` on the right. – Bryan Downing Jun 20 '14 at 01:15
  • 1
    @BryanDowning I forgot to vote up your comment as that is an especially notable use-case, I'll mention it in the answer as well – vol7ron Feb 09 '15 at 16:09
  • It's still not perfect, but it works better if you include "mouseleave" with "mouseup". I actually ended up using "mousemove" and throttled the event. – Mottie Mar 17 '15 at 00:01
  • Do you think this will on touch screen devices?? – Fr0zenFyr Jan 16 '19 at 11:34
8

I mixed vol7ron's answer up a bit, and just replaced the "Resize Action Here" with a simple trigger of the normal "resize" event, so you can attach whatever you want to happen to the resize event "as usual":

$(document).ready(function(){
    $('textarea').bind('mouseup mousemove',function(){
        if(this.oldwidth  === null){this.oldwidth  = this.style.width;}
        if(this.oldheight === null){this.oldheight = this.style.height;}
        if(this.style.width != this.oldwidth || this.style.height != this.oldheight){
            $(this).resize();
            this.oldwidth  = this.style.width;
            this.oldheight = this.style.height;
        }
    });
});

I added the mousemove event so the resizing also fires while dragging the mouse around while resizing, but keep in mind that it fires very often when you move the mouse around.

in this case you might want to put a little delay in actually triggering or handling the resizing event, e.g. replace the above:

$(this).resize();

with:

if(this.resize_timeout){clearTimeout(this.resize_timeout);}
this.resize_timeout = setTimeout(function(){$(this).resize();},100);

example usage, make 2nd textarea grow and shrink with the first one:

$('textarea').eq(0).resize(function(){
    var $ta2 = $('textarea').eq(1);
    $('textarea').eq(1).css('width',$ta2.css('width')).css('height',$ta2.css('height'));
});
MoonLite
  • 4,981
  • 2
  • 21
  • 13
6

another way to do it is by binding to the mouseup event on the textarea. then you can check if size changed.

James
  • 24,676
  • 13
  • 84
  • 130
Guy
  • 71
  • 1
  • 1
3

Resize event doesn't exist for textarea.

The resizeable jQueryPlugin doesn't look native, so we must use alternative.

One way to emulate it is to use the mousedown/click event.
If you want real-time event triggering, you can do it like this:

Updated november 11, 2013:

// This fiddle shows how to simulate a resize event on a
// textarea
// Tested with Firefox 16-25 Linux / Windows
// Chrome 24-30 Linux / Windows

var textareaResize = function(source, dest) {
    var resizeInt = null;
    
    // the handler function
    var resizeEvent = function() {
        dest.outerWidth( source.outerWidth() );
        dest.outerHeight(source.outerHeight());
    };

    // This provides a "real-time" (actually 15 fps)
    // event, while resizing.
    // Unfortunately, mousedown is not fired on Chrome when
    // clicking on the resize area, so the real-time effect
    // does not work under Chrome.
    source.on("mousedown", function(e) {
        resizeInt = setInterval(resizeEvent, 1000/15);
    });

    // The mouseup event stops the interval,
    // then call the resize event one last time.
    // We listen for the whole window because in some cases,
    // the mouse pointer may be on the outside of the textarea.
    $(window).on("mouseup", function(e) {
        if (resizeInt !== null) {
            clearInterval(resizeInt);
        }
        resizeEvent();
    });
};
    
textareaResize($("#input"), $("#output"));

Demo : http://jsfiddle.net/gbouthenot/D2bZd/

gre_gor
  • 6,669
  • 9
  • 47
  • 52
megar
  • 494
  • 5
  • 7
  • For some reason, your jsfiddle example doesn't resize the textarea on the right along with the one on the left. – alexpls Mar 05 '13 at 04:38
  • I just tested it. What browser are you using ? I'm using it on a site and I haven't received any complaint. – megar Mar 07 '13 at 20:19
  • I'm on Chrome latest and there's no mousedown event coming in on the resize... only a mouseup fire. So weird. – louisinhongkong Nov 08 '13 at 10:58
  • I edited my answer to support Chrome latest "bug". I tested with Firefox/Chrome under Linux/Windows 7. – megar Nov 11 '13 at 16:07
2

I wrote this answer to another version of the same question. looks like it's old news in here. I like to stick to vanilla js for whatever reason, so here's a tidy little solution in vanilla:

<textarea
  onmousedown="storeDimensions(this)"
  onmouseup="onresizeMaybe(this)"
></textarea>

<script>
  function storeDimensions(element){
    element.textWidth = element.offsetWidth;
    element.textHeight = element.offsetHeight;
    element.value = "is it gonna change? we don't know yet...";
  }
  
  function onresizeMaybe(element){
    if (element.textWidth===element.offsetWidth
     && element.textHeight===element.offsetHeight) 
      element.value = "no change.\n";
    else element.value ="RESIZED!\n";
    
    element.value +=
       `width: ${element.textWidth}\n`
      +`height: ${element.textHeight}`;
  }
</script>

and for homework, use onmousemove to trigger the resize event instead of onmouseup (I didn't need that in my particular case).

if you want to add this to every textarea in the DOM (not really tested):

let elementArray = document.getElementsByTagName("textarea");
for(var i=0; i<elementArray.length; i++){
  elementArray[i].setAttribute("onmousedown", "storeDimensions(this)");
  elementArray[i].setAttribute("onmouseup", "onresizeMaybe(this)");
}

:) hope it helps someone someday... seeing as how this question is now 9 years old.

NOTE: if you're going to want to trigger this on mousemove, the new fangled ResizeObserver(callback).observe(element) approach is great!

Symbolic
  • 693
  • 5
  • 10
1

I find that a mousemove event and a setTimeout combined work nicely for this.

let el = document.querySelector('textarea')
let resizeFn = ()=>{}
let timeout = null

el.addEventListener('mousemove',()=>{
    timeout && clearTimeout(timeout)
    timeout = setTimeout(resizeFn,250)
 })
seanmart
  • 11
  • 1
1

Not as beautiful and dynamic but it works as expected.

$('.classname').mouseup(function(){
    $('.classname').css('height', $(this).height());
});
hires125
  • 11
  • 1
0

thanks to MoonLite - Your script is working fine, but sometimes, if You do a quick increasing-resize the mouse pointer is outside the textarea on mouseup and the wished function is not triggered. So I added a mouseup event on the containing element to make it work reliable.

.

 
        $('textarea_container').bind('mouseup', function()
        { YourCode ; } ) ;
'
Krishan
  • 17
  • 2
0

FireFox now supports MutationObserver events on textareas and this seems to work quite well. Chrome sadly still needs a workaround.

Based on the other answers on this page, here's a refactored and updated version, that triggers a window resize event when a textarea is resized.

I've also added an event listener for the mouse leaving the window which is needed in an iFrame to detect when the textarea becomes larger than the frame.

(function(textAreaChanged){
    function store(){
        this.x = this.offsetWidth;
        this.y = this.offsetHeight;
    }

    function textAreaEvent(){
        if (this.offsetWidth !== this.x || this.offsetHeight !== this.y) {
            textAreaChanged();
            store.call(this);
        }
    }

    $('textarea').each(store).on('mouseup mouseout',textAreaEvent);

    $(window).on('mouseup',textAreaEvent);

})(function(){
    $(window).trigger('resize');
});

In IE9 and above we can do the same without jQuery.

(function(textAreaChanged){
    function store(){
        this.x = this.offsetWidth;
        this.y = this.offsetHeight;
    }

    function textAreaEvent(){
        if (this.offsetWidth !== this.x || this.offsetHeight !== this.y) {
            textAreaChanged();
            store.call(this);
        }
    }

    Array.prototype.forEach.call(
        document.querySelectorAll('textarea'),
        function (el){
            el.addEventListener('mouseup',   textAreaEvent);
            el.addEventListener('mouseout',  textAreaEvent);
        }
    );

    window.addEventListener('mouseup',textAreaEvent)

})(function(){
    //trigger window resize
    var event = document.createEvent('Events');
    event.initEvent('resize', true, false);
    window.dispatchEvent(event);
});
David Bradshaw
  • 11,859
  • 3
  • 41
  • 70
-3

You need to first make the textarea resizable before issuing the resize event. You can do that by using jQuery UI resizable() and inside it you can call the resize event.

$("textarea").resizable({
    resize: function() {
        $("body").append("<pre>resized!</pre>");
    }
});

Check working example at http://jsfiddle.net/HhSYG/1/

Hussein
  • 42,480
  • 25
  • 113
  • 143
  • 6
    Looks good, doesn't look like a native textarea in my browser tho (chrome, mac) – Doug Molineux Apr 06 '11 at 17:28
  • It doesn't matter. You still need to use resizable() to get cross browser support. – Hussein Apr 06 '11 at 17:35
  • Crap, so the ` – metrobalderas Apr 06 '11 at 17:48
  • 1
    I think this no longer works (currently testing it in JQuery 1.8 – Adonis K. Kakoulidis Feb 14 '13 at 01:34
  • 7
    This didn't work for me in either Firefox or Chrome. The text areas look awful and the resize handle doesn't appear at all. I'm using jQuery 1.9.1 and jQuery UI 1.10.0. – Steve Mar 22 '13 at 11:45
  • 1
    even though the fiddle shows the stylesheet you should mention that this stylesheet is necessary. Without the stylesheet it does not work... – Naxos84 Sep 06 '18 at 10:19