Writing the Perfect jQuery Plugin

by Justin Meyer

Writing the Perfect jQuery Plugin

Justin Meyer jQuery is an excellent DOM abstraction, but compared to other libraries, it leaves much to desire towards building complex, reusable functionality. There's lots of good examples and resources, but most of them fall short in providing a pattern that is

posted in Development on October 11, 2010 by Justin Meyer

jQuery is an excellent DOM abstraction, but compared to other libraries,
it leaves much to desire towards building complex, reusable
functionality. There’s lots of good examples and resources, but most of
them fall short in providing a pattern that is:

  • extensible – you can add new features or derive new
    functionality from old functionality.
  • Organized – the plugin is structured without a lot of anonymous
  • Destroyable – you can remove the plugin without lingering side
  • Deterministic – find out what’s going on where.

Publication’s Purpose

My goal for this article is two-fold:

  1. Raise the bar for what’s considered a “quality” widget.
  2. Demonstrate a simple ‘perfect’ plugin pattern.

You can find all the source code and examples in this
But before we get into it, some throat clearing …

Perfect Perspective

The perfect plugin is many things. Unfortunately, it would take me
months to cover important techniques such as:

  • Progressive enhancement
  • Event oriented architecture
  • High performance plugins

Futhermore, I’m focusing on a very specific type of plugin – widget
plugins. Widget plugins listen to events and change the behavior of the

Fortunately, this covers a lot of what beginner jQuery-ers want to build
and the plugins people share. Tabs, grids, tree, tooltips, contextmenus
are all widget plugins.

Prior Patterns

There’s a lot of other widget patterns. The following are some solid
low-level writeups:

We’ll extend on these ideas to add some important features.

Finally, there are tools that do provide these characteristics:

I will write about these at the end of the article and why you should
use them.

Problem Plugins

There are serious problem with how many people build jQuery widgets. The
following could be a first cut of a context menu that shows content in
an element and removes it when someone clicks away.

$.fn.contextMenu = function(content){
  var el = this[0];
      if(ev.target != el){


This code might be fine for now, but what if you wanted to:

  • Remove the plugin? How are you going to remove the event listener on
    the document? It’s going to keep el in memory until the page
  • Change show and hide to fade in and out.
  • If you saw this happening, how could you find this code?

The Perfect Pattern

To illustrate the perfect-plugin-pattern, I’ll use a basic tabs widget
that we’ll extend to a history tabs. Lets start with what a first
attempt at a Tabs might be:

(function() {
  // returns the tab content for a tab
  var tab = function(li) {
    return $(li.find("a").attr("href"))

  // deactivate the old active tab, mark the li as active
  activate = function(li) {

  // activates the tab on click
  tabClick = function(ev) {

  // a simple tab plugin
  $.fn.simpleTab = function() {

    this.each(function() {
      var el = $(this);

      el.addClass("tabs").delegate("li", "click",tabClick)
          .each(function() {


I’m using as an example a simple tabs that we will extend to a history

You can see this “Simple Tab” at the top of the example

Although we’ll add an additional 150 lines it takes to make this the
‘perfect’ plugin. At the end of this article, I’ll show you how to get
this back down to 20 lines and still be perfect.


We want to make a history enabled tabs with our plugin. So, we should
start by making our base tabs widget extendable.

There’s a lot of techniques out there for extending JavaScript objects.
But, JavaScript provides us a fast and preferred technique – prototypal

The first thing we’ll do is make a tabs constructor function that we can
use. I’ll namespace it with my company name so there are no conflicts:

Jptr = {};

Jptr.Tabs = function(el, options) {
  if (el) {
      this.init(el, options)

   name: "jptr_tabs",
   init: function(el, options) {}

Now I’ll create a skeleton of the history tabs widget. I’ll make the
HistoryTabs extend the base Tabs widget.

Jptr.HistoryTabs =
  function(el, options) {
    if (el) {
        this.init(el, options)

Jptr.HistoryTabs.prototype = new Jptr.Tabs();

$.extend(Jptr.HistoryTabs.prototype, {
 name: "jptr_history_tabs"

And, I’ll use this handy little plugin creator to turn this class into a
jQuery plugin:

$.pluginMaker = function(plugin) {

  // add the plugin function as a jQuery plugin
  $.fn[plugin.prototype.name] = function(options) {

    // get the arguments 
    var args = $.makeArray(arguments),
        after = args.slice(1);

    return this.each(function() {

      // see if we have an instance
      var instance = $.data(this, plugin.prototype.name);
      if (instance) {

        // call a method on the instance
        if (typeof options == "string") {
          instance[options].apply(instance, after);
        } else if (instance.update) {

          // call update on the instance
          instance.update.apply(instance, args);
      } else {

        // create the plugin
        new plugin(this, options);

I can use pluginMaker to turn Jptr.Tabs and Jptr.HistoryTabs into jQuery
widgets like:


This allows us to add tabs to an element like:


And call methods on it like:


So, we now have two extendable classes, that we’ve turned into jQuery
plugins. Our classes don’t do anything yet, but that’s ok, we’ll take
care of that later.


It’s great if we know, just by looking at the DOM, which objects are
controlling which elements. To help with this, we’ll:

  • Save a reference to the element on the widget
  • Save the plugin instance in the element’s data
  • Add the name of the widget to the element

Jptr.Tabs init method now looks like:

  init : function(el, options){

    this.element = $(el);



This makes it much easier to debug our widget. Just by looking at the
html, we can see which widgets are where. If we want more information on
the widget, we can just do:

$('element').data('name') //-> widget

To get our widget back.

Finally, if we get a widget, we know where to look to see which element
the widget is on (ie, widget.element).


For big apps, it’s important to let multiple plugins to operate on the
same element or elements. This is especially needed for behavioral or
event-oriented plugins.

For this to work, you need to be able to add and remove plugins on the
same element without affecting the element or the other plugins.

Unfotunately, most jQuery plugins expect you to remove the element
entirely to teardown the plugin. But what if you want to teardown (ie,
destroy) the plugin without removing the element?

With most plugins, to teardown the plugin, you simply have to remove its
event handlers. So, the tricky part is knowing when to remove the

You need to be able to remove a plugin both programatically and when the
element it operates on is removed.

We’ll listen for a ‘destroyed’ event that happens when an element is
removed from the page via the jQuery modifiers: .remove, .html, etc.
This will call our teardown method.

We’ll also add a destroy function that removes the event handlers and
calls teardown.

Our Tabs widget becomes:

$.extend(Jptr.Tabs.prototype, {
  init : function(el, options){
    // add the class, save the element
    this.element = $(el).addClass(this.name);

    // listen for destroyed, call teardown
        $.proxy(this.teardown, this));

    // call bind to attach events   

  bind: function() {  },

  destroy: function() {

  // set back our element
  teardown: function() {
    this.element = null;
  unbind: function() {  }

Phew, this is a lot of code, but it’s worth it. We made sure that our
widgets clean themselves up when their element is removed from the page.
Further, we made it so we can remove the widget programatically like:

// or like:


Now we just have to add our functionality back in. Tabs now looks like:

$.extend(Jptr.Tabs.prototype, {

    // the name of the plugin
    name: "jptr_tabs",

    // Sets up the tabs widget
    init: function(el, options) {
        this.element = $(el).addClass(this.name);
            $.proxy(this.teardown, this));

        // activate the first tab 

        // hide other tabs
        var tab = this.tab;
        this.element.children("li:gt(0)").each(function() {
    // bind events to this instance's methods
    bind: function() {
        this.element.delegate("li", "click", 
            $.proxy(this.tabClick, this));

    // call destroy to teardown while leaving the element
    destroy: function() {
        this.element.unbind("destroyed", this.teardown);
    // remove all the functionality of this tabs widget
    teardown: function() {
        $.removeData(this.element[0], this.name);
        this.element.removeClass(this.name + " tabs");
        this.element = null;

        var tab = this.tab;

        // show all other tabs
            .each(function() {
    unbind: function() {
    // helper function finds the tab for a given li
    tab: function(li) {
        return $(li.find("a").attr("href"))
    // on an li click, activates new tab  
    tabClick: function(ev) {

    //hides old activate tab, shows new one
    activate: function(el) {

Notice how functions are clearly labeled and are not in anonymous
functions! Although longer, this code is much more readable.

Extensible Cont

Finally, we want to make our history tab. The code looks like:

Jptr.HistoryTabs.prototype = new Jptr.Tabs();    

$.extend(Jptr.HistoryTabs.prototype, {
  name: "jptr_history_tabs",

  // listen for hashchange
  bind: function() {
        $.proxy(this.hashchange, this));

  // clean up listening for hashchange.
  // this is really important
  unbind: function() {
    $(window).unbind("hashchange", this.hashchange);

  // activates the tab represented by the hash
  hashchange: function() {
    var hash = window.location.hash;
    this.activate(hash === '' || hash === '#' ? 
               this.element.find("li:first") : 
               this.element.find("a[href=" + hash + "]")

Notice how easy it is to convert a normal tabs to a history enabled
tabs. Of course, inheritence isn’t necessarily the best
but sometimes it is. The “perfect-plugin-pattern” gives you inheritence
by default. Use it or don’t. Don’t cost nothin.

Also notice how this tabs widget will unbind the window hashchange event
handler if the element is removed, or the plugin is destroyed.

Widget Factories

This pattern is VERY similar to jQueryUI’s widget and JavaScriptMVC’s
controller. They both provide extendable, deterministic, destroyable
widgets. But controller has one (in our opinion) critical advantage – it
will automatically unbind event handlers.

This allows a tab’s widget with controller to look like:

// create a new Tabs class

  // initialize code
  init : function(el){

    // activate the first tab
    this.activate( $(el).children("li:first") )

    // hide other tabs
    var tab = this.tab;

  // helper function finds the tab for a given li
  tab : function(li){
    return $(li.find("a").attr("href"))

  // on an li click, activates new tab  
  "li click" : function(el, ev){

  //hides old activate tab, shows new one
  activate : function(el){

// creates a Tabs on the #tabs element

Controller recognizes function names like “li click” and will
automatically unbind them when the controller is destroyed.


I believe in widget factories, and it’s dissapointing that they aren’t
used more in third party jQuery plugins. Our hope is that articles like
this can highlight their importance both by showing the necessity of the
features they provide and how cumbersome it is to do it yourself.

Regardless of your choice of ‘widget factory’, it’s important think
about the characteristics that practically every jQuery widget should

If you need the destroyed event, you can find it
on jQuery++‘s site.

If you’re looking for our implementation of this pattern, you can find it in
CanJS’s can.Control.

blog comments powered by Disqus

Using CanJS 2.2 with StealJS and NPM

David Lueckeposted in Development, Open Source on April 23, 2015 by David LueckeCanJS can be used in many different module formats like AMD and CommonJS and package managers like Bower and NPM. In this post we will talk about using CanJS with the new StealJS and NPM.

Set Algebra with can-set

Justin Meyerposted in Development, Open Source on April 22, 2015 by Justin Meyercan-set is a client and server side JavaScript utility that makes set algebra easy. This article talks about the design goals of can-set and introduces a few cases where you might find it useful.

CanJS 2.2 Release

Justin Meyerposted in Development, Open Source, Uncategorized on April 5, 2015 by Justin MeyerCanJS 2.2 is out. It's awesome. This article covers the top 10 enhancements added since 2.1. Some of the improvements include Browserify and StealJS support, can-EVENT arguments, observable promises, and in-page automatically rendered templates. The article includes a lot of good JSBins to learn from too.

Contact Us
(312) 620-0386 | contact@bitovi.com
 or cancel