Published on June 30, 2008

This post was previously on the Pathfinder Software site. Pathfinder Software changed its name to Orthogonal in 2016. Read more.

I recently asserted that open-source plugins are sometimes more trouble than they’re worth. Nevertheless, I’ve found one unexpected benefit of jQuery’s plugin mechanism: its ability to keep me focused on reusable components rather than one-off, procedural routines.

Because jQuery doesn’t ship with any general-purpose way of simulating classical inheritance, it’s easy to fall into the trap of writing procedural code with no eye toward re-use. When your first pass at solving a given problem often takes only a few lines of code, it seems like too much overhead to wrap those lines in any sort of object.

But then you decide to layer on some effects … or there’s a new requirement to retain state across sessions by calling on a cookies plugin … or you end up with a new use case that would require a subclass of your existing code – if it had been written as a class in the first place. By this point, it becomes obvious that your behavior layer is poorly organized, hard to maintain, and inexorably tied to a specific use case. That’s when you roll up your shirtsleeves and start refactoring.

Lately, though, I’ve found a better pattern. If I take care never to write a single line of code without packaging it as a plugin, the architectural part of my brain kicks in. I’m able to zoom back from the problem at hand to a more general case and abstract things accordingly. All of this is OOP 101, of course, but it bears repeating in the context of the deceptively simple jQuery.

So what is a jQuery plugin?

A jQuery plugin is simply a method that’s added to the jQuery object itself. Such methods get called on a collection of DOM nodes, operate on those nodes and then return them for further method chaining. Plugins are the easiest way to write reusable modules in jQuery. The jQuery object even offers a convenience method for attaching new plugins to itself: the fn method.

The Learning jQuery website offers fantastic advice for packaging your behaviors into plugins: A Plugin Development Pattern. Take a look and give it a shot.

Plugins in action

To demonstrate the advantage of this pattern, I offer up “before” and “after” views of a quick little jQuery function I wrote to build an expandable list of recent blog posts on this very website. The original, procedural code looked like this:

//progressively show recent posts
	var list = $('#rail div.railBlock#recentposts ul');
		var $this = $(this);
		if (i > 3) {

‘ ) .find(‘li.styleAsLink’).click(function() { list.find(‘li’).show(); $(this).remove(); }) ; }());

After being rewritten as a plugin, it looks like this:

//a plugin to hide some elements in a list
//and provide a one-time link to show them
$.fn.pfd_singlehideshow = function(options) {
	var opts = $.extend({}
	  , $.fn.pfd_singlehideshow.defaults, options

	var list = $(this);
		var $this = $(this);
		if (i > opts.hideIndex) {

  • + opts.showMoreText + ‘

‘) .find(‘li.’ + opts.showMoreClass).click(function() { list.find(‘li’).show(); $(this).remove(); }) ; }; $.fn.pfd_singlehideshow.defaults = { hideIndex: 3 , showMoreText: ‘show more recent posts’ , showMoreClass: ‘link’ }; $(‘#rail div.railBlock#recentposts ul’).pfd_singlehideshow();

Granted, this is hardly some universal object that can be adapted to a ton of different uses. But the mere act of refashioning it into a plugin forced me to separate behavior from implementation. Any specific CSS classes and text blocks became part of the options bundle. So did the parameter that controls how many items in the list are closed by default. The result is a reusable component that could be used to hide and later show many varieties of list data, not just blog headlines. Granted, the code assumes it will be operating on an unordered list, but that would be easy to abstract out to the options bundle. From here, we could easily add some additional parameters to build a progressive hide/show feature that reveals the hidden list items in chunks instead of all at once.