How can I fire an event if a CSS class is added or changed using jQuery?
Does changing of a CSS class fire the jQuery change()
event?

- 5,753
- 72
- 57
- 129

- 2,599
- 4
- 18
- 7
-
87 years later, with the fairly wide adoption of MutationObservers in modern browsers, the accepted answer here should really updated to be [Mr Br's](http://stackoverflow.com/a/24284069/663246). – joelmdev Jun 15 '16 at 18:11
-
This might help you. http://stackoverflow.com/questions/2157963/is-it-possible-to-listen-to-a-style-change-event – PSR Jan 31 '17 at 07:18
-
In completion to Jason's answer, i found this : https://stackoverflow.com/a/19401707/1579667 – Benj Oct 27 '17 at 12:24
13 Answers
Whenever you change a class in your script, you could use a trigger
to raise your own event.
$(this).addClass('someClass');
$(mySelector).trigger('cssClassChanged')
....
$(otherSelector).bind('cssClassChanged', data, function(){ do stuff });
but otherwise, no, there's no baked-in way to fire an event when a class changes. change()
only fires after focus leaves an input whose input has been altered.
$(function() {
var button = $('.clickme')
, box = $('.box')
;
button.on('click', function() {
box.removeClass('box');
$(document).trigger('buttonClick');
});
$(document).on('buttonClick', function() {
box.text('Clicked!');
});
});
.box { background-color: red; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="box">Hi</div>
<button class="clickme">Click me</button>

- 51,583
- 38
- 133
- 185
-
4What's the deal with triggering the event which then calls a function? Why not call the function directly, instead of triggering it? – RamboNo5 Dec 23 '09 at 01:11
-
44Triggering is a mechanism that will allow certain elements to "subscribe" to an event. that way, when the event is triggered, those events can all happen at once and run their respective functionality. for instance, if i have one object that changes from red to blue and three objects waiting for it to change, when it changes, i can just trigger the `changeColor` event, and all those objects subscribing to that event can react accordingly. – Jason Dec 23 '09 at 01:32
-
1Seems a bit strange that the OP wants to listen to a 'cssClassChanged' event; surely the class was added as a result of some other 'application' event such as 'colourChanged' which would make more sense to announce with trigger as I can't quite imagine why anything would be interested in specifically a className change, it's more the result of the classNameChange surely? – Richard Scarrott Feb 08 '13 at 14:46
-
If it was specifically a className change that was of interest then I'd imagine decorating jQuery.fn.addClass to trigger 'cssClassChanged' would be more sensible like @micred said – Richard Scarrott Feb 08 '13 at 14:48
-
6@riscarrott i don't presume to know the OP's application. I'm just presenting them with the concept of pub/sub and they can apply it however they'd like. Disputing what the actual event name should be with the amount of info given is silly. – Jason Mar 07 '13 at 17:35
-
It's not correct that there is no baked-in way to fire and event. I have added answer bellow which explains Mutation Observers a bit, http://stackoverflow.com/questions/1950038/jquery-fire-event-if-css-class-changed/24284069#24284069 . With mutation observers you can get real events on attribute change, without need to trigger anything manually. – Mr Br Nov 26 '14 at 13:10
-
...with tons of extra code, less cross-browser support, less flexibility, and events firing every time something changes on the page leading to a decrease in performance. MutationObservers are cool for sure, though. – Jason Nov 30 '14 at 08:08
-
It's future, most of latest browser support it, and it's appended to every element only in example, in answer I said it's not suggested to do it, you should append it only to elements on which you need listener...how browsers support it check out at http://caniuse.com/#feat=mutationobserver This way your are making it more generic, instead of triggering event every time manually, for me that is right approach. I am just interested if you would accept it if (when) jQuery adds it as default feature... – Mr Br Nov 30 '14 at 10:36
IMHO the better solution is to combine two answers by @RamboNo5 and @Jason
I mean overridding addClass function and adding a custom event called cssClassChanged
// Create a closure
(function(){
// Your base, I'm in it!
var originalAddClassMethod = jQuery.fn.addClass;
jQuery.fn.addClass = function(){
// Execute the original method.
var result = originalAddClassMethod.apply( this, arguments );
// trigger a custom event
jQuery(this).trigger('cssClassChanged');
// return the original result
return result;
}
})();
// document ready function
$(function(){
$("#YourExampleElementID").bind('cssClassChanged', function(){
//do stuff here
});
});

- 30,436
- 41
- 178
- 315

- 6,149
- 2
- 41
- 47
-
This indeed sounds like the best approach, but although I bind the event only to "#YourExampleElementID", it appears that all class changes (i.e., on any of the elements on my page) are handled by this handler... any thoughts? – Filipe Correia Mar 08 '13 at 13:12
-
It works fine for me @FilipeCorreia . Can you please provide a jsfiddle with replicating your case? – Arash Milani Mar 09 '13 at 07:19
-
@Goldentoa11 You should take time some evening or weekend and monitor everything that happens on a typical pageload which uses advertising heavily. You will be blown away by the volume of scripts attempting (sometimes unsuccessfully in the most spectacular way) to do things like this. I've run across pages which fire tens of DOMNodeInserted/DOMSubtreeModified events per second, totaling hundreds of events by the time you get to `$()`, when the real action starts. – L0j1k Sep 26 '14 at 18:16
-
You would presumably also want to support triggering the same event on removeClass – Darius Apr 01 '15 at 14:34
-
4Arash, I guess I understand why @FilipeCorreia was experiencing some issues with this approach: if you bind this `cssClassChanged` event to an element, you must be aware that it will be fired even when its child change their class. Therefore if for example you don't want to fire this event for them, just add something like `$("#YourExampleElementID *").on('cssClassChanged', function(e) { e.stopPropagation(); });` after your bind. Anyway, really nice solution, thanks! – tonix Mar 13 '17 at 15:53
-
Beware of a Stack Overflow if you were to alter the css class in the listener; The Solution works perfect for me! – Wayne May 08 '19 at 23:53
If you want to detect class change, best way is to use Mutation Observers, which gives you complete control over any attribute change. However you need to define listener yourself, and append it to element you are listening. Good thing is that you don't need to trigger anything manually once listener is appended.
$(function() {
(function($) {
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
$.fn.attrchange = function(callback) {
if (MutationObserver) {
var options = {
subtree: false,
attributes: true
};
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(e) {
callback.call(e.target, e.attributeName);
});
});
return this.each(function() {
observer.observe(this, options);
});
}
}
})(jQuery);
//Now you need to append event listener
$('body *').attrchange(function(attrName) {
if(attrName=='class'){
alert('class changed');
}else if(attrName=='id'){
alert('id changed');
}else{
//OTHER ATTR CHANGED
}
});
});
In this example event listener is appended to every element, but you don't want that in most cases (save memory). Append this "attrchange" listener to element you want observe.

- 3,831
- 1
- 20
- 24
-
1this seems like it is doing the exact same thing that the accepted answer is doing, but with more code, unsupported on some browsers, and with less flexibility. the only benefit this appears to have is that it will fire _every time_ something changes on the page, which will absolutely destroy your performance... – Jason Nov 30 '14 at 08:06
-
10Your statement in answer is incorrect @Json, this is actually the way to do it if you don't want to active any trigger manually, but have it active automatically. It's not only benefit it's the benefit, cos this was asked in question. Second, this was just an example, and as it says in example it's not suggested to append event listener to every element but only to elements you want to listen, so I don't understand why will it destroy performance. And last thing, it's future, most of latest browser support it, http://caniuse.com/#feat=mutationobserver .Please reconsider edit, it's right way. – Mr Br Nov 30 '14 at 10:28
-
1The [insertionQ library](https://github.com/naugtur/insertionQuery) lets you catch DOM nodes showing up if they match a selector. It has wider browser support because it doesn't use `DOMMutationObserver`. – Dan Dascalescu Aug 28 '15 at 04:07
-
This is a great solution. In particular for starting and stopping canvas or SVG animations when a class is added or removed. In my case for making sure they are not running when scrolled out of view. Sweet! – BBaysinger Aug 24 '18 at 20:17
-
1For 2019, this should be the accepted answer. All major browsers seem to support Mutation Observers now, and this solution doesn't require to fire events manually or rewrite basic jQuery functionality. – sp00n Mar 05 '19 at 13:11
I would suggest you override the addClass function. You can do it this way:
// Create a closure
(function(){
// Your base, I'm in it!
var originalAddClassMethod = jQuery.fn.addClass;
jQuery.fn.addClass = function(){
// Execute the original method.
var result = originalAddClassMethod.apply( this, arguments );
// call your function
// this gets called everytime you use the addClass method
myfunction();
// return the original result
return result;
}
})();
// document ready function
$(function(){
// do stuff
});
-
16Combining this with Jason's $(mySelector).trigger('cssClassChanged') would be the best approach I think. – kosoant Dec 23 '09 at 06:40
-
4There's a plugin that does this generically: http://github.com/aheckmann/jquery.hook/blob/master/jquery.hook.js – Jerph Nov 01 '10 at 17:27
-
37
-
1
-
1For reference, you are using the Proxy Pattern http://en.wikipedia.org/wiki/Proxy_pattern – Darius Apr 01 '15 at 14:32
Just a proof of concept:
Look at the gist to see some annotations and stay up-to-date:
https://gist.github.com/yckart/c893d7db0f49b1ea4dfb
(function ($) {
var methods = ['addClass', 'toggleClass', 'removeClass'];
$.each(methods, function (index, method) {
var originalMethod = $.fn[method];
$.fn[method] = function () {
var oldClass = this[0].className;
var result = originalMethod.apply(this, arguments);
var newClass = this[0].className;
this.trigger(method, [oldClass, newClass]);
return result;
};
});
}(window.jQuery || window.Zepto));
The usage is quite simple, just add a new listender on the node you want to observe and manipulate the classes as usually:
var $node = $('div')
// listen to class-manipulation
.on('addClass toggleClass removeClass', function (e, oldClass, newClass) {
console.log('Changed from %s to %s due %s', oldClass, newClass, e.type);
})
// make some changes
.addClass('foo')
.removeClass('foo')
.toggleClass('foo');

- 32,460
- 9
- 122
- 129
-
This worked for me, except I could not read old or new class with the removeClass method. – slashdottir Feb 20 '14 at 22:06
-
1@slashdottir Can you create a fiddle and explain **what** exactly *doesn't work*. – yckart Sep 18 '14 at 19:06
-
Yeah... does not work. TypeError: this[0] is undefined in «return this[0].className;» – Pedro Ferreira Feb 21 '16 at 18:29
-
it works but sometimes (why ?), `this[0]` is undefined ... simply replace the end of the lines with `var oldClass` and `var newClass` with the following assignment: `= (this[0] ? this[0].className : "");` – fvlinden Sep 29 '18 at 08:04
using latest jquery mutation
var $target = jQuery(".required-entry");
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.attributeName === "class") {
var attributeValue = jQuery(mutation.target).prop(mutation.attributeName);
if (attributeValue.indexOf("search-class") >= 0){
// do what you want
}
}
});
});
observer.observe($target[0], {
attributes: true
});
// any code which update div having class required-entry which is in $target like $target.addClass('search-class');

- 2,439
- 29
- 32
-
Nice solution, I'm using it. However, I'm using react and one of the problem is that I add an observer each time the web element is virtually generated. Is there a way to check if an observer is already present? – Mikaël Mayer Aug 25 '16 at 02:35
-
I think this has been depreciated and should not be used according to [link]https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/observe – WebDude0482 Jan 06 '17 at 18:37
-
@WebDude0482 MutationObserver.observe is not deprecated as it is an "Instance Method" of the "MutationObserver". See https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver – nu everest Jan 10 '17 at 16:51
There is one more way without triggering an custom event
A jQuery Plug-in to monitor Html Element CSS Changes by Rick Strahl
Quoting from above
The watch plug-in works by hooking up to DOMAttrModified in FireFox, to onPropertyChanged in Internet Explorer, or by using a timer with setInterval to handle the detection of changes for other browsers. Unfortunately WebKit doesn’t support DOMAttrModified consistently at the moment so Safari and Chrome currently have to use the slower setInterval mechanism.

- 4,769
- 8
- 56
- 82
change()
does not fire when a CSS class is added or removed or the definition changes. It fires in circumstances like when a select box value is selected or unselected.
I'm not sure if you mean if the CSS class definition is changed (which can be done programmatically but is tedious and not generally recommended) or if a class is added or removed to an element. There is no way to reliably capture this happening in either case.
You could of course create your own event for this but this can only be described as advisory. It won't capture code that isn't yours doing it.
Alternatively you could override/replace the addClass()
(etc) methods in jQuery but this won't capture when it's done via vanilla Javascript (although I guess you could replace those methods too).

- 616,129
- 168
- 910
- 942
Good question. I'm using the Bootstrap Dropdown Menu, and needed to execute an event when a Bootstrap Dropdown was hidden. When the dropdown is opened, the containing div with a class name of "button-group" adds a class of "open"; and the button itself has an "aria-expanded" attribute set to true. When the dropdown is closed, that class of "open" is removed from the containing div, and aria-expanded is switched from true to false.
That led me to this question, of how to detect the class change.
With Bootstrap, there are "Dropdown Events" that can be detected. Look for "Dropdown Events" at this link. http://www.w3schools.com/bootstrap/bootstrap_ref_js_dropdown.asp
Here is a quick-and-dirty example of using this event on a Bootstrap Dropdown.
$(document).on('hidden.bs.dropdown', function(event) {
console.log('closed');
});
Now I realize this is more specific than the general question that's being asked. But I imagine other developers trying to detect an open or closed event with a Bootstrap Dropdown will find this helpful. Like me, they may initially go down the path of simply trying to detect an element class change (which apparently isn't so simple). Thanks.

- 2,355
- 5
- 37
- 57
If you need to trigger a specific event you can override the method addClass() to fire a custom event called 'classadded'.
Here how:
(function() {
var ev = new $.Event('classadded'),
orig = $.fn.addClass;
$.fn.addClass = function() {
$(this).trigger(ev, arguments);
return orig.apply(this, arguments);
}
})();
$('#myElement').on('classadded', function(ev, newClasses) {
console.log(newClasses + ' added!');
console.log(this);
// Do stuff
// ...
});

- 1,482
- 1
- 19
- 19
You can bind the DOMSubtreeModified event. I add an example here:
HTML
<div id="mutable" style="width:50px;height:50px;">sjdfhksfh<div>
<div>
<button id="changeClass">Change Class</button>
</div>
JavaScript
$(document).ready(function() {
$('#changeClass').click(function() {
$('#mutable').addClass("red");
});
$('#mutable').bind('DOMSubtreeModified', function(e) {
alert('class changed');
});
});

- 333
- 3
- 5
- 18
if you know a what event changed the class in the first place you may use a slight delay on the same event and the check the for the class. example
//this is not the code you control
$('input').on('blur', function(){
$(this).addClass('error');
$(this).before("<div class='someClass'>Warning Error</div>");
});
//this is your code
$('input').on('blur', function(){
var el= $(this);
setTimeout(function(){
if ($(el).hasClass('error')){
$(el).removeClass('error');
$(el).prev('.someClass').hide();
}
},1000);
});

- 1,287
- 2
- 17
- 31
var timeout_check_change_class;
function check_change_class( selector )
{
$(selector).each(function(index, el) {
var data_old_class = $(el).attr('data-old-class');
if (typeof data_old_class !== typeof undefined && data_old_class !== false)
{
if( data_old_class != $(el).attr('class') )
{
$(el).trigger('change_class');
}
}
$(el).attr('data-old-class', $(el).attr('class') );
});
clearTimeout( timeout_check_change_class );
timeout_check_change_class = setTimeout(check_change_class, 10, selector);
}
check_change_class( '.breakpoint' );
$('.breakpoint').on('change_class', function(event) {
console.log('haschange');
});

- 132,869
- 46
- 340
- 423

- 131
- 2