Grow your CSS skills. Land your dream job.

Custom Events are Pretty Cool

Published by Chris Coyier

Let's say you are working on a web application in jQuery and you are tasked with writing an accordion suited to the needs of your web app. You decide to make it into a plugin. That way anywhere in this app that needs an accordion, they can load this plugin and call it upon semantic markup that is ready to become an accordion. Then ta-da, they have a lovely working accordion.

Now another developer is using your accordion and they want to be able to Ajax load some content into one of the sections of the accordion, but only when that section is opened. Together you decide that you should keep your code separate. The generic functionality of how an accordion works should be separate from code specific to one accordion on one page of an app.

Callbacks, the traditional way

One way to approach that would be to write "callbacks" into your plugin. The other developer would specify the name of a function that she wants run when certain actions happen on that accordion. So the calling of it might be like:

$(".accordion").accordion({
  panelOpen: myPanelOpenCallback,
  panelClose: myPanelCloseCallback;
});

And they would have created those callback functions themselves:

function myPanelOpenCallback() {
  // Do Ajax stuff 
}

Then the plugin itself would honor those callbacks in its related internal functions:

$.fn.accordion = function(options) {
    
	return this.each(function(i, el) {

	  var base = el;
	  
	  base.init = function() {
	  	// Do initialization stuff
	  };
	  
	  base.openPanel = function(panel) {
	  	// Open panel
		
		// Do callback
		options.panelOpen.call();
	  };
	  
	  base.closePanel = function(panel) {
	  	// Open panel
		
		// Do callback
		options.panelClose.call();
	  };
	  
	  base.init();
	       
	});
  
};

View Demo of Callback Model

Custom Events, a better way

Now let's say a third developer gets involved, and they also want to write a bit of JavaScript that reacts to a panel opening as well. For the sake of a use case, say what's inside the accordion panels are settings, and this developer wants to save those settings whenever keys are opened or closed automatically.

Now we're in an interesting position. We've already defined our callback for accordion panels opening and closing. So in the callback model, these developers are going to have to get together on that callback and run both of their code in that one callback. Not that big of a deal, but now we're forced to mix code when that might not be ideal. Remember we started this whole thing off by separating specific functionalities.

Here's where custom events are super rad. Instead of firing off a specified callback, the accordion functionality plugin fires off a custom event. Custom events are just like any other event (e.g. click) only they are only declared and called programmatically.

First, callbacks are gone, we just call the accordion plugin without them:

$(".accordion").accordion();

Now in place of where we called the callbacks, we'll trigger our Custom Event. Basically, just make up a name that makes sense (like you are naming a function).

// OUT
// options.panelOpen.call();

// IN
panel.trigger("panelOpen");

Now our other developers can bind their stuff to this custom event and do their own thing.

$(".panel").on("panelOpen", function() {
   // Developer 1: do Ajax stuff
});

// Meanwhile, in another part of town...
$(".panel").on("panelOpen", function() {
   // Developer 2: do saving stuff
});

Yay for freedom! Yay for separation of functionality!

In my opinion custom events are just better all around. I do think they require a bit more communication though. You'll probably have to write up some comments somewhere that explain what custom events are fired and when and make that easy to discover.

View Demo of Custom Events model

More Information

The scenario outlined above is very simple. The following two articles go way more into depth about Custom Events including more complex examples and more information on how they work.

Comments

  1. Even better would be to namespace your events.

    $(element).on("open.panel", function () {
    
    });

    Where the “open” event is namespaced under “panel.”

  2. hanso wijgnaard
    Permalink to comment#

    These remind me of eventListeners with the exception that you can’t tell who is listing to what. I find that a bit weird.

    Let’s say, 2 buttons both broadcast a ‘press’ event when they get pressed.

    One button needs to change the backgound-color of the body while the other needs to change the div height.

    If you can’t specify that the body needs to listen to only one button it will react no matter which button is pressed. Same goes for the div of course.

  3. jQuery is very useful JS script library. Using it helped me a lot in development .

  4. Dor
    Permalink to comment#

    Actually, I disagree. This approach encourages APIs which lie about their dependencies.

    What do I mean by that? A developer wanders onto a site using your .accordion plugin. This is what he sees:

    
    $('.accordion').accordion();
    

    Without looking at the source code for that plugin, or some sort of documentation, the developer can’t ever know that the plugin actually fires the said events. However, with the callback approach:

    
    $('.accordion').accordion(whenOpened, whenClosed);
    

    Here, the plugin explicitly declared what it needed in order to operate. The API is truthful, it doesn’t lie by saying “I don’t have any functions that can go with me, I am just an accordion”, it now says “I am an accordion, I support a whenOpened and whenClosed callback functions, that are getting called when these events happen

    • I agree with this. Chris, I’d be interested to hear – do you think the custom events method would create more spaghetti-esque code? By that, I mean – in your own file (not in the plugin), have lots of seemingly random custom event listeners ( using .on() ), without them being in a structure that is related to the plugin (the callback approach)? I can absolutely see the advantage you brought up in your article (and thanks for the info, btw – super rad), but I think if this method is used a lot throughout a project, the code would start to become very difficult to manage.

      Thanks!

    • Neil
      Permalink to comment#

      While I agree with you somewhat, the fact that you mention API and documentation, I would expect a decent plugin to list its API in document form, therefore I don’t see this as too big a problem.

  5. J
    Permalink to comment#

    I guess we can use a combination of both. Jquery plugins have a tradtion of using callbacks, so I’m inclined to keep it this way.
    The event call after the plugin initialization can be overlooked, while callbacks in options won’t.

    A quick implementation : http://jsbin.com/usaboz/2

  6. Permalink to comment#

    i love that
    thnx chris ::D

  7. A brilliant article, custom events do give us developers so much more freedom. Thanks for sharing this information, i’ll be forwarding it onto a few friends who I know will also enjoy reading this.

  8. A quick message to Chris regarding this comment form of yours. While I love the look and layout of this comment form, I’m not too fond of the icons you’ve used to explain what each textbox is for. I had to THINK about what goes where… I worked out the name and email icons okay but I struggled to guess the third website URL icon. I know your a big believer in your blogs accesability so I thought I should point this small issue out to you as I’m sure others have had the same problem. Even if you just added a very simple hover popup for the icons that would solve the problem. Personally speaking, I’d change the third url icon to a chain/link icon as everyone would understand that.

    I hope you don’t mind me posting this here, I know its not related to this article specifically so after you’ve read this I don’t mind if you delete it. Also, just incase you do have a hover discription on each textbox and its actually my own browser thats at fault, for your referrence I’m using Firefox version 3.6.

    • Permalink to comment#

      If you used a modern web browser, you’d see the preview text in the text fields. If you were visually impaired, you’d hear the descriptive text associated with the fields. I think it’s time for you to update.

    • Permalink to comment#

      If you used a modern web browser, you’d see the preview text in the text fields. If you were visually impaired, you’d hear the descriptive text associated with the fields. I think it’s time for you to update.
      —–
      ^ that’s a rude and churlish answer to a valid user interface complaint, especially since Firefox 3.6 IS a valid browser, and not everyone is in a situation where they can just “upgrade”

      The text disappears when the field has focus, so, unless you memorized what text was there before, you won’t know what to type there and the ‘icon’ doesnt help one bit.

      Not a big deal, since that field isnt required, but why bother??

  9. Permalink to comment#

    jQuery UI’s widget factory supports triggering events as part of the widget. It also allows for binding the events as part of the initialization object.

  10. Permalink to comment#

    These are totally awesome! I’m playing with custom events now.

  11. Permalink to comment#

    Custom events and modular, extensible code are all pretty awesome things…I just wish people would realize they are just now becoming aware of features and principles that have been present in MooTools for more than 6 years – this.fireEvent(‘customEventName’). If you want even more flexible, extensible code that has all the features mentioned in the article (and much more) I encourage you to give MooTools a try, it is simply beyond jQuery’s limited DOM-centered scope in so many ways (I recently built a whole node.js framework with it because it rocks on the server side as well!)

  12. Bert de Vries
    Permalink to comment#

    Just wanted to say: Merry Christmas to all and a Happy New Year.

  13. What?

  14. Permalink to comment#

    Chris! I liked your method – when you hover the title, the read more link also is hovered. Can you write me how is it made? thanks in advance

  15. Permalink to comment#

    I’m a bit confused. This will only work if the component is programmed for raising the custom events, right?
    Thanks.

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".