jQuery plugin development has evolved over the past few years. We no longer have just one way to write plugins, but many. In reality, certain plugin design patterns might work better for a particular problem or component than others.
Some developers may wish to use the jQuery UI widget factory; it’s great for complex, flexible UI components. Some may not.
Some might like to structure their plugins more like modules (similar to the module pattern) or use a more modern module format such as AMD.
Some might want their plugins to harness the power of prototypal inheritance. Others may wish to use custom events or Publish/Subscribe to communicate from plugins to the rest of their app. And so on.
I began to think about plugin patterns after noticing a number of efforts to create a one-size-fits-all jQuery plugin boilerplate. While such a boilerplate is a great idea in theory, the reality is that we rarely write plugins in one fixed way, using a single pattern all the time.
Let us assume that we’ve tried our hand at writing our own jQuery plugins at some point and we’re comfortable putting together something that works. It’s functional. It does what it needs to do, but perhaps we feel it could be structured better. Maybe it could be more flexible or could be designed to address more of the issues developers commonly run into. If this sounds familiar, then you might find this chapter useful. In it, we’re going to explore a number of jQuery plugin patterns that have worked well for other developers in the wild.
Note: This chapter is targeted at intermediate to advanced developers, although we will briefly review some jQuery plugin fundamentals to begin.
jQuery plugins have few concrete rules, which is one of the reasons for the incredible diversity in how they are implemented across the community. At the most basic level, we can write a plugin simply by adding a new function property to jQuery’s jQuery.fn object, as follows:
An alternative way to write this pattern would be to use jQuery.extend(), which enables us to define multiple functions at once and which sometimes make more sense semantically:
We have now reviewed some jQuery plugin fundamentals, but a lot more could be done to take this further. A Lightweight Start is the first complete plugin design pattern we’ll be exploring and it covers some best practices that we can use for basic everyday plugin development, taking into account common gotchas worth applying.
While most of the patterns below will be explained, I recommend reading through the comments in the code, because they will offer more insight into why certain best practices are applied.
I should also mention that none of this would be possible without the previous work, input and advice of other members of the jQuery community. I’ve listed them inline with each pattern so that one can read up on their individual work if interested.
‘A Lightweight Start’ Pattern
Let’s begin our deeper look at plugin patterns with something basic that follows best practices (including those in the jQuery plugin-authoring guide). This pattern is ideal for developers who are either new to plugin development or who just want to achieve something simple (such as a utility plugin). A Lightweight Start uses the following:
Common best practices such as a semi-colon placed before the functions invocation (we’ll go through why in the comments below)
window, document, undefined passed in as arguments.
A basic defaults object.
A simple plugin constructor for logic related to the initial creation and the assignment of the element to work with.
Extending the options with defaults.
A lightweight wrapper around the constructor, which helps to avoid issues such as multiple instantiations.
Adherence to the jQuery core style guidelines for maximized readability.
While the jQuery plugin authoring guide is a great introduction to plugin development, it doesn’t help obscure away common plugin plumbing tasks that we have to deal with on a regular basis.
The jQuery UI Widget Factory is a solution to this problem that helps us build complex, stateful plugins based on object-oriented principles. It also eases communication with our plugins instance, obfuscating a number of the repetitive tasks that we would have to code when working with basic plugins.
Stateful plugins help us keep track of their current state, also allowing us to change properties of the plugin after it has been initialized.
One of the great things about the Widget Factory is that the majority of the jQuery UI library actually uses it as a base for its components. This means that if we’re looking for further guidance on structure beyond this pattern, we won’t have to look beyond the jQuery UI repository on GitHub (https://github.com/jquery/jquery-ui).
This jQuery UI Widget Factory pattern covers almost all of the supported default factory methods, including triggering events. As per the last pattern, comments are included for all of the methods used and further guidance is given in the inline comments.
As we’ve previously covered in the book, namespacing our code is a way to avoid collisions with other objects and variables in the global namespace. They’re important because we want to safeguard our plugin from breaking in the event that another script on the page uses the same variable or plugin names as ours. As a good citizen of the global namespace, we must also do our best not to prevent other developers scripts from executing because of the same issues.
Objects (or, rather, object literals) can be used to create nested namespaces, such as namespace.subnamespace.pluginName and so on. But to keep things simple, the namespacing boilerplate below should show us everything we need to get started with these concepts.
Custom Events Plugin Pattern (With The Widget factory)
The basic idea here is that objects in a page can publish event notifications when something interesting occurs in our application. Other objects then subscribe to (or listen) for these events and respond accordingly. This results in the logic for our application being significantly more decoupled, as each object no longer needs to directly communicate with another.
In the following jQuery UI widget factory pattern, we’ll implement a basic custom event-based Publish/Subscribe system that allows our plugin to subscribe to event notifications from the rest of our application, which will be responsible for publishing them.
Prototypal Inheritance With The DOM-To-Object Bridge Pattern
Yepnope.js author Alex Sexton and jQuery team member Scott Gonzalez have looked at this topic in detail. In sum, they discovered that for organized modular development, clearly separating the object that defines the logic for a plugin from the plugin-generation process itself can be beneficial.
The benefit is that testing our plugins code becomes significantly easier and we are also able to adjust the way things work behind the scenes without altering the way that any object APIs we implement are used.
In Sexton’s article on this topic, he implemented a bridge that enables us to attach our general logic to a particular plugin, which we’ve implemented in the pattern below.
One of the other advantages of this pattern is that we don’t have to constantly repeat the same plugin initialization code, thus ensuring that the concepts behind DRY development are maintained. Some developers might also find this pattern easier to read than others.
If you liked the idea of generating plugins based on objects in the last design pattern, then you might be interested in a method found in the jQuery UI Widget Factory called $.widget.bridge.
Moreover,$.widget.bridge provides access to a number of other capabilities, including the following:
Both public and private methods are handled as one would expect in classical OOP (i.e. public methods are exposed, while calls to private methods are not possible).
Automatic protection against multiple initializations.
Automatic generation of instances of a passed object, and storage of them within the selection’s internal $.data cache.
Options can be altered post-initialization.
For further information on how to use this pattern, please see the inline comments below:
jQuery mobile is a jQuery project framework that encourages the design of ubiquitous web applications that work both on popular mobile devices and platforms and on the desktop. Rather than writing unique applications for each device or OS, we simply write the code once and it should ideally run on many of the A-, B- and C-grade browsers out there at the moment.
The fundamentals behind jQuery mobile can also be applied to plugin and widget development.
What’s interesting in this next pattern is that although there are small, subtle differences in writing a “mobile”-optimized widget, those familiar with using the jQuery UI Widget Factory pattern from earlier should be able to grasp this in next to no time.
The mobile-optimized widget below has a number of interesting differences than the standard UI widget pattern we saw earlier:
$.mobile.widget is referenced as an existing widget prototype from which to inherit. For standard widgets, passing through any such prototype is unnecessary for basic development, but using this jQuery-mobile specific widget prototype provides internal access to further “options” formatting.
In _create(), a guide is provided on how the official jQuery mobile widgets handle element selection, opting for a role-based approach that better fits the jQM mark-up. This isn’t at all to say that standard selection isn’t recommended, only that this approach might make more sense given the structure of jQuery Mobile pages.
Guidelines are also provided in comment form for applying our plugin methods on pagecreate as well as for selecting the plugin application via data roles and data attributes.
We can also self-initialize this widget whenever a new page in jQuery Mobile is created. jQuery Mobile’s page plugin dispatches a create event when a jQuery Mobile page (found via the data-role=”page”attribute) is first initialized. We can listen for that event (called “pagecreate”) and run our plugin automatically whenever a new page is created.
We can now simply reference the script containing our widget and pagecreate binding in a page running jQuery Mobile site, and it will automatically run like any other jQuery Mobile plugin.
RequireJS And The jQuery UI Widget Factory
As we covered in the section on Modern Module Design Patterns, RequireJS is an AMD-compatible script loader that provides a clean solution for encapsulating application logic inside manageable modules.
It’s able to load modules in the correct order (through its order plugin), simplifies the process of combining scripts via its excellent r.js optimizer and provides the means for defining dynamic dependencies on a per-module basis.
In the boilerplate pattern below, we demonstrate how an AMD (and thus RequireJS) compatible jQuery UI widget can be defined that does the following:
Allows the definition of widget module dependencies, building on top of the previous jQuery UI Widget Factory pattern presented earlier.
Demonstrates one approach to passing in HTML template assets for creating templated widgets (using Underscore.js micro-templating).
Includes a quick tip on adjustments that we can make to our widget module if we wish to later pass it through to the RequireJS optimizer.
Globally And Per-Call Overridable Options (Best Options Pattern)
For our next pattern, we’ll look at an optimal approach to configuring options and defaults for a plugin. The way most of us are probably familiar with defining plugin options is to pass through an object literal of defaults to $.extend(), as demonstrated in our basic plugin boilerplate.
If, however, we’re working with a plugin with many customizable options that we would like users to be able to override either globally or on a per-call level, then we can structure things a little more optimally.
Instead, by referring to an options object defined within the plugin namespace explicitly (for example, $fn.pluginName.options) and merging this with any options passed through to the plugin when it is initially invoked, users have the option of either passing options through during plugin initialization or overriding options outside of the plugin (as demonstrated here).
In this pattern, similar to Alex Sexton’s prototypal inheritance plugin pattern, logic for our plugin isn’t nested in a jQuery plugin itself. We instead define our plugin logic using a constructor and an object literal defined on its prototype. jQuery is then used for the actual instantiation of the plugin object.
Customization is taken to the next level by employing two little tricks, one of which we’ve seen in previous patterns:
Options can be overridden both globally and per collection of elements/
Options can be customized on a per-element level through HTML5 data attributes (as shown below). This facilitates plugin behavior that can be applied to a collection of elements but then customized inline without the need to instantiate each element with a different default value.
We don’t see the latter option in the wild too often, but it can be a significantly cleaner solution (as long as we don’t mind the inline approach). If wondering where this could be useful, imagine writing a draggable plugin for a large set of elements. We could go about customizing their options as follows:
At the end of the day, design patterns are just one facet to writing maintainable jQuery plugins. There are a number of other factors worth considering and I would like to share my own criteria for selecting third-party plugins to address some of the other concerns. I hope this helps increase the overall quality of your plugin projects:
Does the plugin follow a consistent code style guide such as the jQuery Core Style Guidelines? If not, is your code at least relatively clean and readable?
Which versions of jQuery is the plugin compatible with? Has it been tested with the latest jQuery-git builds or latest stable? If the plugin was written before jQuery 1.6, then it might have issues with attributes and properties, because the way they were approached changed in that release.
New versions of jQuery offer improvements and opportunities for the jQuery project to improve on what the core library offers. With this comes occasional breakages (mainly in major releases) as we move towards a better way of doing things. I’d like to see plugin authors update their code when necessary or, at a minimum, test their plugins with new versions to make sure everything works as expected.
If the plugin needs to perform tasks that require extensive processing or heavily manipulation of the DOM, one should follow best practices for benchmarking to help minimize this. Use jsPerf.com to test segments of the code to a) how well it performs in different browsers and b) discover what, if anything, might be optimized further.
If the intension is for other developers to use the plugin, ensure that it’s well documented. Document the API and how the plugin is to be used. What methods and options does the plugin support? Does it have any gotchas that users need to be aware of? If users cannot figure out how to use the plugin, they’ll likely look for an alternative. It is also of great help to comment your plugin code. This is by far the best gift you can offer other developers. If someone feels they can navigate your code base well enough to use it or improve it, then you’ve done a good job.
Likelihood of maintenance
When releasing a plugin, estimate how much time may be required for maintenance and support. We all love to share our plugins with the community, but one needs to set expectations for ones ability to answer questions, address issues and make continuous improvements. This can be done simply by stating the project intentions for maintenance support upfront in the README file.
In this chapter, we explored several time-saving design patterns and best practices that can be employed to improve how jQuery plugins can be written. Some are better suited to certain use cases than others, but I hope on the whole these patterns are useful.
Remember, when selecting a pattern, it is important to be practical. Don’t use a plugin pattern just for the sake of it, rather, invest time in understanding the underlying structure, and establish how well it solves your problem or fits the component you’re trying to build.