159

How do I detect change event on textarea using javascript?
I'm trying to detect how many characters left is available as you type.

I tried using the onchange event, but that seems to only kick in when focus is out.

Nakilon
  • 34,866
  • 14
  • 107
  • 142
teepusink
  • 27,444
  • 37
  • 107
  • 147

10 Answers10

144

The best way to do this, cross-browser: use a combination of the input and onpropertychange events, like so:

var area = container.querySelector('textarea');
if (area.addEventListener) {
  area.addEventListener('input', function() {
    // event handling code for sane browsers
  }, false);
} else if (area.attachEvent) {
  area.attachEvent('onpropertychange', function() {
    // IE-specific event handling code
  });
}

The input event takes care of IE9+, FF, Chrome, Opera and Safari, and onpropertychange takes care of IE8 (it also works with IE6 and 7, but there are some bugs).

The advantage of using input and onpropertychange is that they don't fire unnecessarily (like when pressing the Ctrl or Shift keys); so if you wish to run a relatively expensive operation when the textarea contents change, this is the way to go.

Now IE, as always, does a half-assed job of supporting this: neither input nor onpropertychange fires in IE when characters are deleted from the textarea. So if you need to handle deletion of characters in IE, use keypress (as opposed to using keyup / keydown, because they fire only once even if the user presses and holds a key down).

Source: http://www.alistapart.com/articles/expanding-text-areas-made-elegant/

EDIT: It seems even the above solution is not perfect, as rightly pointed out in the comments: the presence of the addEventListener property on the textarea does not imply you're working with a sane browser; similarly the presence of the attachEvent property does not imply IE. If you want your code to be really air-tight, you should consider changing that. See Tim Down's comment for pointers.

John
  • 1
  • 13
  • 98
  • 177
Vicky Chijwani
  • 10,191
  • 6
  • 56
  • 79
  • 1
    This is the best approach. I don't like the inferences here (browser support for `addEventListener` does not imply support for the `input` event, or vice versa); feature detection would be better. See [this blog post](https://web.archive.org/web/20130215103706/http://whattheheadsaid.com/2011/10/update-html5-oninput-event-plugin-for-jquery) for a discussion of this. – Tim Down Jan 03 '13 at 23:20
  • Totally agree with Tim on this one. `oninput` is how we ought to do this, but your probably shouldn't be using `addEventListener` as your test for browser-support. +1 in any case. – Ben D May 16 '13 at 21:41
  • 1
    Disagree, input won't take care of IE9. Cut/Paste via contextmenu unfortunately is also input, and so is backspace. I didn't bother to test, but I wouldn't place any money on the bet that IE10+ fixed that issue. – Stefan Steiger Sep 15 '15 at 06:33
  • 2
    @StefanSteiger which is why my answer suggests also using the `keypress` event to handle that case in IE9 (and possibly later versions too). – Vicky Chijwani Sep 15 '15 at 08:54
  • [`input` event](https://developer.mozilla.org/en-US/docs/Web/Events/input) handler can also be defined by implementing the `.oninput` object property. – handle Sep 30 '16 at 09:06
109

You will need to use onkeyup and onchange for this. The onchange will prevent context-menu pasting, and the onkeyup will fire for every keystroke.

See my answer on How to impose maxlength on textArea for a code sample.

Community
  • 1
  • 1
Josh Stodola
  • 81,538
  • 47
  • 180
  • 227
  • 3
    Just wanted to emphasize what Josh already said, that you should be using keyup, not keydown for this: keydown seems to be called before the change is actually made to the textarea, so you'll be using the wrong length (and you don't really know how off you are: could be typing or deleting, and could have text selected meaning it's more than just +/- 1). – brianmearns Apr 26 '12 at 15:24
  • 74
    I'm giving a -1 here, sorry! `onkeyup` is a terrible event for input detection. Use `oninput` and `onpropertychange` (for IE support). – Andy E May 14 '12 at 09:52
  • 6
    The "only" problem is `onchange` is **NOT** fired when a context-menu cut/paste occurs. – Tom Aug 19 '12 at 18:33
  • @Tom: Use onmousemove to catch cut ;) – Stefan Steiger Oct 13 '12 at 09:52
  • 4
    It's much more responsive to use onkeydown and a setTimeout so that you get instant change detection rather than waiting for the key to be released. If you also need to catch cut and paste, use the cut and paste events. – Kevin B Jan 03 '13 at 22:27
  • 1
    Warning: onkeyup can give you trouble. Example: lets say you should only do something if the input contents changed. If you assume a keyup will change the input, its not true. Put focus on the input. Use "tab" to move to the next field. Now use "shift+tab" to go back to the input. keyup fires yet the input wasnt actually changed by the user. – Zig Mandel Apr 07 '15 at 15:21
  • Correct me if I'm wrong, but I believe there is an `onpaste` event. – Dendromaniac May 04 '15 at 17:20
  • @ZigMandel For that use-case, why not just store the length on the input and compare it to the new length every time the event fires? – whirlwin Jan 06 '16 at 09:31
  • 1
    `onkeyup is a terrible event for input detection`: The only terrible thing around here is the design decisions browser vendors and the lala-land-situated spec authors took. To quote Vicky Chijwani from below: `It's 2012, the post-PC era is here, and we still have to struggle with something as basic as this. This ought to be very simple.`. Nothing more to say here really... At least, I hope all non-Chromium browsers **die** and we can have a better future. Otherwise... – user2173353 Aug 24 '16 at 08:18
  • `onkeyup is a terrible event for input detection`... @Andy is totally right and `onInput` is the way to do it and the purpose of that event. @user, the real world works this way, it's also terrible you can't drink coca-cola straight from the tap, or that tomorrow might rain even if you had great plans to go to the beach. If you had read the event documentation 5 years ago, you wouldn't have struggled. `onInput` is around since 2011, and it works in all browsers https://caniuse.com/#feat=input-event #RTFM – rupps Dec 01 '17 at 13:04
  • Surprise surprise, an old answer brought to light by more evangelical nonsense. This is so *terrible* because it worked perfectly fine ten years ago and still works today? Sounds awful! SMH – Josh Stodola Dec 01 '17 at 21:31
24
  • For Google-Chrome, oninput will be sufficient (Tested on Windows 7 with Version 22.0.1229.94 m).
  • For IE 9, oninput will catch everything except cut via contextmenu and backspace.
  • For IE 8, onpropertychange is required to catch pasting in addition to oninput.
  • For IE 9 + 8, onkeyup is required to catch backspace.
  • For IE 9 + 8, onmousemove is the only way I found to catch cutting via contextmenu

Not tested on Firefox.

    var isIE = /*@cc_on!@*/false; // Note: This line breaks closure compiler...

    function SuperDuperFunction() {
        // DoSomething
    }


    function SuperDuperFunctionBecauseMicrosoftMakesIEsuckIntentionally() {
        if(isIE) // For Chrome, oninput works as expected
            SuperDuperFunction();
    }

<textarea id="taSource"
          class="taSplitted"
          rows="4"
          cols="50"
          oninput="SuperDuperFunction();"
          onpropertychange="SuperDuperFunctionBecauseMicrosoftMakesIEsuckIntentionally();"
          onmousemove="SuperDuperFunctionBecauseMicrosoftMakesIEsuckIntentionally();"
          onkeyup="SuperDuperFunctionBecauseMicrosoftMakesIEsuckIntentionally();">
Test
</textarea>
Kijewski
  • 25,517
  • 12
  • 101
  • 143
Stefan Steiger
  • 78,642
  • 66
  • 377
  • 442
8

I know this isn't exactly your question but I thought this might be useful. For certain applications it is nice to have the change function fire not every single time a key is pressed. This can be achieved with something like this:

var text = document.createElement('textarea');
text.rows = 10;
text.cols = 40;
document.body.appendChild(text);

text.onkeyup = function(){
var callcount = 0;
    var action = function(){
        alert('changed');
    }
    var delayAction = function(action, time){
        var expectcallcount = callcount;
        var delay = function(){
            if(callcount == expectcallcount){
                action();
            }
        }
        setTimeout(delay, time);
    }
    return function(eventtrigger){
        ++callcount;
        delayAction(action, 1200);
    }
}();

This works by testing if a more recent event has fired within a certain delay period. Good luck!

user45743
  • 449
  • 1
  • 6
  • 8
7

I know this question was specific to JavaScript, however, there seems to be no good, clean way to ALWAYS detect when a textarea changes in all current browsers. I've learned jquery has taken care of it for us. It even handles contextual menu changes to text areas. The same syntax is used regardless of input type.

    $('div.lawyerList').on('change','textarea',function(){
      // Change occurred so count chars...
    });

or

    $('textarea').on('change',function(){
      // Change occurred so count chars...
    });
Tim Duncklee
  • 1,420
  • 1
  • 23
  • 35
  • 4
    I found that the change event was not more consistent with jQuery than with plain JS. I used jQuery's `bind("input cut paste"...` and it works like a charm - typing, cut & paste using the keyboard or context menu; even drag/drop of text. – Lawrence Dol Feb 13 '13 at 08:47
  • 2
    Unfortunately, FF does not fire `change` event for `textarea`. – dma_k Aug 04 '14 at 11:49
6

You can listen to event on change of textarea and do the changes as per you want. Here is one example.

const textArea = document.getElementById('my_text_area');
textArea.addEventListener('input', () => {
    var textLn =  textArea.value.length;
    if(textLn >= 100) {
        textArea.style.fontSize = '10pt';
    }
})
<html>
    <textarea id='my_text_area' rows="4" cols="50" style="font-size:40pt">
This text will change font after 100.
    </textarea>
</html>
KetZoomer
  • 2,701
  • 3
  • 15
  • 43
Pankaj Manali
  • 668
  • 6
  • 15
1

Keyup should suffice if paired with HTML5 input validation/pattern attribute. So, create a pattern (regex) to validate the input and act upon the .checkValidity() status. Something like below could work. In your case you would want a regex to match length. My solution is in use / demo-able online here.

<input type="text" pattern="[a-zA-Z]+" id="my-input">

var myInput = document.getElementById = "my-input";

myInput.addEventListener("keyup", function(){
  if(!this.checkValidity() || !this.value){
    submitButton.disabled = true;
  } else {
    submitButton.disabled = false;
  }
});
Ronnie Royston
  • 16,778
  • 6
  • 77
  • 91
0

Code I have used for IE 11 without jquery and just for a single textarea:

Javascript:

// Impede que o comentário tenha mais de num_max caracteres
var internalChange= 0; // important, prevent reenter
function limit_char(max)
{ 
    if (internalChange == 1)
    {
        internalChange= 0;
        return;
    }
    internalChange= 1;
    // <form> and <textarea> are the ID's of your form and textarea objects
    <form>.<textarea>.value= <form>.<textarea>.value.substring(0,max);
}

and html:

<TEXTAREA onpropertychange='limit_char(5)' ...
Rogério Silva
  • 121
  • 1
  • 11
-1

Try this one. It's simple, and since it's 2016 I am sure it will work on most browsers.

<textarea id="text" cols="50" rows="5" onkeyup="check()" maxlength="15"></textarea> 
<div><span id="spn"></span> characters left</div>

function check(){
    var string = document.getElementById("url").value
    var left = 15 - string.length;
    document.getElementById("spn").innerHTML = left;
}
default
  • 106
  • 2
  • 10
-11

The best thing that you can do is to set a function to be called on a given amount of time and this function to check the contents of your textarea.

self.setInterval('checkTextAreaValue()', 50);
sth
  • 222,467
  • 53
  • 283
  • 367
Ico
  • 19
  • 1