Using Plugins
Throughout the first six chapters we examined the core components of jQuery. The library is powerful on its own, but its elegant plugin architecture allows developers to extend it with even richer functionality. Hundreds of community‑created plugins exist, ranging from tiny selector helpers to full‑fledged UI widgets. This section explains how to tap into that wealth.
We will cover:
- Downloading and setting up a plugin
- Calling jQuery methods that a plugin provides
- Finding elements with custom selectors defined by plugins
- Adding complex user‑interface behaviour with jQuery UI
- Building mobile‑friendly features with jQuery Mobile
Working with Plugins
Using a jQuery plugin is straightforward: obtain the plugin code, reference it from you're HTML, and invoke the new functionality in your scripts. The Cycle plugin by Mike Alsup turns a static collection of elements into an interactive slideshow. It handles complex demands gracefully but hides that complexity when your needs are simple.
Downloading and Referencing the Cycle Plugin
We install plugins with the npm package manager. A package.json file declares dependencies. After initialising the file, you can add the jQuery dependency:
npm install jquery --save
Then install the Cycle plugin:
npm install jquery-cycle --save
The --save flag adds the packages to package.json. Now include them in your page:
<head>
<meta charset="utf-8">
<title>jQuery Slideshow</title>
<link rel="stylesheet" href="07.css" type="text/css" />
<script src="img/jquery.js"></script>
<script src="img/index.js"></script>
<script src="img/07.js"></script>
</head>
The plugin is now ready for use.
Invoking Plugin Methods
Cycle works on any group of sibling elements. We set up a list of book covers and details:
<ul id="bookList">
<li>
<img src="img/jq-game.jpg" alt="jQuery Game Development Essentials" />
<div class="title">jQuery Game Development Essentials</div>
<div class="author">Salim Arsever</div>
</li>
<li>
<img src="img/jqmobile-cookbook.jpg" alt="jQuery Mobile Cookbook" />
<div class="title">jQuery Mobile Cookbook</div>
<div class="author">Chetan K Jain</div>
</li>
...
</ul>
Light styling displays the books one after another:

Apply the plugin by calling .cycle() on the container:
$(document).ready(function() {
$('#bookList').cycle();
});
That single call transforms the list into an animated slideshow, showing one item at a time with a fade transition every four seconds:

Well‑written plugins deliver professional results with minimal code, yet they offer many options for fine‑tuning.
Specifying Plugin Method Parameters
Passing arguments to a plugin method is the same as with native jQuery methods. Oftan you provide a single object with key‑value pairs. Cycle has over fifty options; here we adjust a few:
$(function() {
$('#bookList').cycle({
timeout: 2000,
speed: 200,
pause: true
});
});
timeout is the millisecond delay between slides, speed the transition duration. pause: true stops the slideshow when the mouse hovers over it.
Modifying Parameter Defaults
Cycle stores its defaults in $.fn.cycle.defaults. You can change them globally:
$.fn.cycle.defaults.timeout = 10000;
$.fn.cycle.defaults.random = true;
$(function() {
$('#bookList').cycle({
timeout: 2000,
speed: 200,
pause: true
});
});
The new timeout of 10000 is ignored because we override it in the call, but random: true takes effect, shuffling the slide order.
Other Plugin Types
Plugins can also enhance jQuery’s selection engine or provide global functions. Cycle, for instance, adds a custom selector.
Custom Selectors
Cycle can be paused and resumed with .cycle('pause') and .cycle('resume'). We add buttons to control the slideshow:
$(function() {
var $slideshow = $('#bookList').cycle({
timeout: 2000,
speed: 200,
pause: true
});
var $panel = $('<div/>')
.attr('id', 'controls')
.insertAfter($slideshow);
$('<button/>')
.text('Pause')
.on('click', function() {
$slideshow.cycle('pause');
})
.appendTo($panel);
$('<button/>')
.text('Resume')
.on('click', function() {
$slideshow.cycle('resume');
})
.appendTo($panel);
});
Cycle’s :paused custom selector lets us find all paused slideshows and resume them together:
$('button.resume-all')
.on('click', function() {
$('ul:paused').cycle('resume');
});
Global Function Plugins
Some plugins introduce functions in the jQuery namespace, useful when no DOM element is involved. The Cookie plugin provides $.cookie(). We can remember that the slideshow was paused:
if ($.cookie('slidesPaused')) {
$slideshow.cycle('pause');
}
To set and clear the cookie:
$('button.pause')
.on('click', function() {
$slideshow.cycle('pause');
$.cookie('slidesPaused', 'y');
});
$('button.resume')
.on('click', function() {
$('ul:paused').cycle('resume');
$.cookie('slidesPaused', null);
});
You can configure cookie expiration and path by passing an options object, for example { path: '/', expires: 7 }.
jQuery UI Plugin Library
While most plugins focus on a single task, jQuery UI is a comprehensive suite of related widgets and interactions. It includes draggable, sortable, resizable components, and full widgets such as buttons, accordion, datepicker, and dialog, plus a rich set of effects.
Effects
jQuery UI extends .animate() to animate colours, classes, and advanced easings.
Colour Animation
With the core effects file included, .animate() can transition properties like backgroundColor and color:
$(function() {
$('#bookList').on('mouseenter mouseleave', 'li', function(e) {
var $title = $(this).find('.title');
if (e.type === 'mouseenter') {
$title.animate({
backgroundColor: '#eee',
color: '#000'
}, 1000);
} else {
$title.animate({
backgroundColor: '#000',
color: '#fff'
}, 1000);
}
});
});

Class Animation
The class methods gain an optional duration argument. Toggling a class becomes animated:
$('h1').on('click', function() {
$(this).toggleClass('highlighted', 'slow');
});

Advanced Easing
jQuery UI provides easing functions like easeInExpo. You can apply them to any animation:
$('h1').on('click', function() {
$(this).toggleClass('highlighted', 'slow', 'easeInExpo');
});
Additional Effects
Individual effect files add transitions such as shake, puff, or transfer. The .effect() method invokes them. Here we shake the Resume button if there is no paused slideshow:
$('button.resume')
.on('click', function(e) {
var $paused = $('ul:paused');
if ($paused.length) {
$paused.cycle('resume');
$.cookie('slidesPaused', null);
} else {
$(e.target).effect('shake', { distance: 10 });
}
});
Interaction Components
The Resizable component lets users change element dimensions by dragging. Apply it with .resizable():
$(function() {
$('#bookList').find('.title').resizable();
});
This adds a resize handle at the bottom‑right corner:

To restrict resizing to the vertical direction, specify the handle:
$('#bookList').find('.title').resizable({ handles: 's' });

Widgets
jQuery UI widgets style and enhance common controls. The Button widget is simple:
$('button').button();
Icons are available from the theme framework:
$('button.pause')
.button({ icons: { primary: 'ui-icon-pause' } });
$('button.resume')
.button({ icons: { primary: 'ui-icon-play' } });

The Slider widget creates an interactive range input. We integrate it with the slideshow:
var $slider = $('<div/>')
.attr('id', 'slideControl')
.slider({
min: 0,
max: $('#bookList li').length - 1,
slide: function(e, ui) {
$('#bookList').cycle(ui.value);
}
})
.appendTo($panel);
To keep the slider in sync when the slideshow advances, use Cycle’s before callback:
$('#bookList').cycle({
before: function(slide) {
$('#slideControl')
.slider('value', $('#bookList li').index(slide));
}
});
jQuery UI ThemeRoller
ThemeRoller (jqueryui.com/themeroller/) generates custom themes for widgets. After picking colours and textures, download a ZIP of stylesheets and images and reference them to instantly change the look of your interface.
jQuery Mobile Plugin Library
jQuery Mobile provides mobile‑optimised components including Ajax navigation, touch events, and responsive widgets. Its main interaction method is via HTML5 data-* attributes.
HTML5 Custom Data Attributes
jQuery Mobile scans for specific data-role and other attributes to enhance pages without JavaScript. For instance, a simple book list beecomes a mobile‑friendly page by declaring data-role="page", data-role="header", and data-role="content".
Mobile Navigation
Links between pages with data-role="page" are automatically handled by Ajax with transitions. You can also include multiple "pages" in one document using anchors.
Interactive Elements
List views are enhanced with data-role="listview" and a filter can be added with data-filter="true". Buttons naturally appear in toolbars, and a back button is added by data-add-back-btn="true".
Advanced Features
jQuery Mobile offers touch‑optimised events (tap, swipe), a ThemeRoller for mobile widgets, and integration with PhoneGap to build native apps.
Developing Plugins
When existing plugins do not fit, you can create your own. This process is similar to writing code that uses plugins. We will cover adding global functions, jQuery object methods, and UI widget‑factory plugins.
Protecting the Dollar Alias
Plugins must assume jQuery is loaded but cannot assume $ is available. Use an immediately invoked function expression (IIFE) to locally define $:
(function($) {
// plugin code
})(jQuery);
Adding New Global Functions
Global utility methods live in the jQuery namespace. Let’s create $.addValues() to compute a sum from an array:
(function($) {
$.addValues = function(array) {
return array.reduce(function(total, current) {
return parseFloat($.trim(current)) + total;
}, 0);
};
})(jQuery);
Now call it: $.addValues([...]).
We can also wrap multiple functions in a namespace object:
(function($) {
$.calc = {
total: function(arr) {
return arr.reduce(function(sum, val) {
return parseFloat($.trim(val)) + sum;
}, 0);
},
average: function(arr) {
if (!Array.isArray(arr)) return '';
return $.calc.total(arr) / arr.length;
}
};
})(jQuery);
Usage: $.calc.total(array) and $.calc.average(array).
Adding jQuery Object Methods
To add instance methods, extend $.fn. A swapClass method that toggles two class names demonstrates the pattern:
(function($) {
$.fn.swapClass = function(first, second) {
return this.each(function() {
var $el = $(this);
if ($el.hasClass(first)) {
$el.removeClass(first).addClass(second);
} else if ($el.hasClass(second)) {
$el.removeClass(second).addClass(first);
}
});
};
})(jQuery);
Important: always call .each() to enforce implicit iteration and return this to support method chaining.
Flexible Method Parameters
Provide an options object with sensible defaults. A shadow plugin that overlays semitransparent clones illustrates this:
(function($) {
$.fn.shadow = function(options) {
var defaults = {
copies: 5,
opacity: 0.1,
offset: function(idx) {
return { x: idx, y: idx };
}
};
var opts = $.extend({}, defaults, options);
return this.each(function() {
var $source = $(this);
for (var i = 0; i < opts.copies; i++) {
var pos = opts.offset(i);
$source.clone()
.css({
position: 'absolute',
left: $source.offset().left + pos.x,
top: $source.offset().top + pos.y,
zIndex: -1,
opacity: opts.opacity
})
.appendTo('body');
}
});
};
})(jQuery);
Users can customise the effect: $('h1').shadow({ copies: 3, opacity: 0.25 }). The offset option is a callback, allowing complete control of positioning.
To make defaults publicly customisable, expose them on the plugin:
$.fn.shadow.defaults = { ... };
Using the jQuery UI Widget Factory
The widget factory ($.widget) creates stateful plugins that automatically handle options merging, method chaining, and destruction. We’ll build a tooltip widget.
Define the widget with a namespace:
(function($) {
$.widget('custom.tooltip', {
_create: function() {
this._box = $('<div/>')
.addClass('custom-tooltip ui-widget ui-state-highlight ui-corner-all')
.hide()
.appendTo('body');
this.element
.addClass('custom-tooltip-trigger')
.on('mouseenter.customtooltip', $.proxy(this._open, this))
.on('mouseleave.customtooltip', $.proxy(this._closed, this));
},
_open: function() {
if (this.options.disabled) return;
var pos = this.element.offset();
this._box
.css({
left: pos.left + this.options.offsetX,
top: pos.top + this.element.height() + this.options.offsetY
})
.text(this.options.content(this.element))
.show();
this._trigger('open');
},
_closed: function() {
this._box.hide();
this._trigger('close');
},
destroy: function() {
this._box.remove();
this.element
.removeClass('custom-tooltip-trigger')
.off('.customtooltip');
this._superApply(arguments);
},
options: {
offsetX: 10,
offsetY: 10,
content: function(el) {
return $(el).data('tooltip-text');
}
}
});
})(jQuery);
Call $('a').tooltip() to activate. Methods like destroy, disable, enable, open, and close are available. Custom events tooltipopen and tooltipclose are triggered.
Plugin Design Recommendations
- Protect the
$alias with an IIFE. - Add only one property to
$.fnor$; use a namespace object. - Expose default options publicly (
$.fn.myPlugin.defaults). - Return
thisfor chaining; use.each()for implicit iteration. - Use callbacks for flexible behaviour.
- Leverage the widget factory for complex, stateful components.
- Maintain unit tests (e.g., QUnit) and version control (Git).
- Choose a clear license (e.g., MIT).
Distributing Plugins
Proper documentation (e.g., JSDoc) and hosting on npm or GitHub make your plugin accessible. Include examples and describe every parameter and option.
Advanced Selectors and Traversing
Since jQuery 1.3, the Sizzle engine has powered $() by parsing selectors and using efficient DOM methods. Combining Sizzle with jQuery’s traversal methods provides powerful element‑finding capabilities.
We will examine dynamic table filtering, row striping, custom selectors, and performance optimisation.
Dynamic Table Filtering
Given a table of news items and topic links, we filter rows on click:
$(function() {
$('#topics a').on('click', function(e) {
e.preventDefault();
var topic = $(this).text();
$(this).addClass('selected')
.siblings('.selected').removeClass('selected');
$('#news tr').show();
if (topic !== 'All') {
$('#news tr:has(td)').filter(function() {
return $(this).children(':nth-child(4)').text() !== topic;
}).hide();
}
});
});
This hides rows whose fourth column does not match the selected topic.
Striping Table Rows
A simple striping uses :nth-child(even), but grouping two rows at a time and respecting <tbody> boundaries requires a custom filter:
$(function() {
function stripe() {
$('#news tbody').each(function() {
$(this).children().has('td')
.filter(function(i) { return (i % 4) < 2; })
.addClass('alt');
});
}
stripe();
});
When combined with filtering, re‑apply striping after topic changes, and only consider visible rows:
function stripe() {
$('#news tr.alt').removeClass('alt');
$('#news tbody').each(function() {
$(this).children(':visible').has('td')
.filter(function(i) { return (i % 4) < 2; })
.addClass('alt');
});
}
Custom Selector Plugins
We can extend jQuery’s expr[':'] object to define new pseudo‑classes. A :group(n) selector groups elements by index:
(function($) {
$.extend($.expr[':'], {
group: function(el, idx, matches) {
var num = parseInt(matches[3], 10);
return Number.isInteger(num) &&
($(el).index() - 1) % (num * 2) < num;
}
});
})(jQuery);
Now $('#news tr:group(3)') selects rows in alternating groups of three.
Selector Performance
Sizzle favours native .querySelectorAll() when possible. Custom jQuery selectors (like :eq, :odd) force a slower loop‑and‑test approach. Prefer standard CSS selectors and move custom filters to traversal methods. Use benchmarking tools like jsPerf to verify gains.
DOM Traversal Internals
Each jQuery object maintains a stack via .prevObject. Methods like .end() pop the stack, while .addBack() merges the current set with the previous one. This supports fluid chaining.
Writing a Traversal Plugin
A .column() method finds all cells in the same table column:
(function($) {
$.fn.column = function() {
var $cells = $();
this.each(function() {
var $td = $(this).closest('td, th');
if ($td.length) {
var col = $td[0].cellIndex + 1;
var $colCells = $td.closest('table')
.find('td, th')
.filter(':nth-child(' + col + ')');
$cells = $cells.add($colCells);
}
});
return this.pushStack($cells);
};
})(jQuery);
Usage: $('td').column().addClass('highlight').
Traversal Performance Tips
- Chain methods to avoid re‑selecting elements.
- Cache frequently used jQuery objects.
For example, store var $news = $('#news'); and reuse it.
Further Reading
See Appendix B and the official jQuery documentation for complete lists of selectors and traversal methods.
Exercises
- Stripe rows with classes
altandalt-2in groups of three. - Create a
:containsExactly(text)custom selector. - Rewrite the topic filter using
:containsExactly(). - Write a
.grandparent()traversal plugin. - Benchmark
.closest()vs..parents()for finding an ancestor table with jsPerf. - Benchmark
:last-child,:nth-child(),.last(), and:lastfor the last cell in each row.