jQuery Writing Your Own Plugin
Writing your own jQuery plugin lets you package reusable functionality into a clean, chainable method. You can use it across pages, share it with a team, or even publish it for other developers. This topic walks you through the complete structure of a properly written jQuery plugin.
Minimal Plugin Structure
(function($) {
$.fn.pluginName = function() {
return this.each(function() {
// Your code here — runs for each matched element
});
};
})(jQuery);
The outer (function($) { ... })(jQuery) is a self-executing function that safely maps jQuery to $ inside the plugin — important for WordPress and multi-library environments.
Diagram: Plugin Wrapper Structure
(function($) { ← accepts jQuery as $
$.fn.myPlugin = function() { ← adds method to jQuery.fn
return this.each(function() { ← loops over each element
// code per element
}); ← return this enables chaining
};
})(jQuery); ← passes jQuery as argument
Step 1 — A Simple Plugin with No Options
(function($) {
$.fn.highlight = function() {
return this.each(function() {
$(this).css({
"background-color": "yellow",
"font-weight": "bold"
});
});
};
})(jQuery);
// Usage:
$("p").highlight();
$(".note").highlight().addClass("marked");
Step 2 — Plugin with Default Options
Real plugins accept options so the user can customise behaviour. Use $.extend() to merge user options with defaults.
(function($) {
$.fn.colorBox = function(options) {
var settings = $.extend({
background: "lightblue",
color: "black",
padding: "10px"
}, options);
return this.each(function() {
$(this).css({
"background-color": settings.background,
"color": settings.color,
"padding": settings.padding
});
});
};
})(jQuery);
// Usage with default settings:
$(".box").colorBox();
// Usage with custom options:
$(".box").colorBox({ background: "salmon", color: "white" });
Diagram: Options Merge in a Plugin
defaults: { background:"lightblue", color:"black", padding:"10px" }
user opts: { background:"salmon", color:"white" }
$.extend({}, defaults, options):
{ background:"salmon", color:"white", padding:"10px" }
↑ overwritten ↑ overwritten ↑ kept from defaults
Step 3 — Plugin with Callback Support
(function($) {
$.fn.fadeToggleCustom = function(options) {
var settings = $.extend({
speed: 400,
onDone: function() {} // empty default callback
}, options);
return this.each(function() {
$(this).fadeToggle(settings.speed, settings.onDone);
});
};
})(jQuery);
// Usage:
$(".panel").fadeToggleCustom({
speed: 600,
onDone: function() {
console.log("Animation complete!");
}
});
Step 4 — Plugin that Returns a Value (Getter)
Most plugins return this for chaining. But sometimes a plugin needs to return a value — like reading a property. When doing this, do NOT return this.
(function($) {
$.fn.getTotalWidth = function() {
var total = 0;
this.each(function() {
total += $(this).outerWidth(true);
});
return total; // returns a number, not jQuery object
};
})(jQuery);
// Usage:
var totalWidth = $(".card").getTotalWidth();
console.log("Total width of all cards: " + totalWidth + "px");
Complete Plugin Example — Tooltip
(function($) {
$.fn.simpleTooltip = function(options) {
var settings = $.extend({
text: "",
position: "top",
delay: 200
}, options);
return this.each(function() {
var $el = $(this);
var text = settings.text || $el.attr("data-tooltip") || "";
var $tip = $("<div class='s-tooltip'>" + text + "</div>");
$el.mouseenter(function() {
$("body").append($tip);
var offset = $el.offset();
$tip.css({
top: offset.top - $tip.outerHeight() - 8,
left: offset.left
}).fadeIn(settings.delay);
});
$el.mouseleave(function() {
$tip.fadeOut(settings.delay, function() {
$(this).remove();
});
});
});
};
})(jQuery);
// Usage:
$("[data-tooltip]").simpleTooltip();
$(".help-icon").simpleTooltip({ text: "Click for help", delay: 100 });
Best Practices When Writing Plugins
- Always wrap in
(function($) { ... })(jQuery);to protect the$alias. - Always return
this(orthis.each()) for chainability. - Use
$.extend({}, defaults, options)to merge settings without modifying defaults. - Prefix your plugin name to avoid conflicts:
$.fn.myappSlidernot$.fn.slider. - Support callback functions so users can hook into plugin events.
- Use
data()to store plugin state on the element itself.
Preventing Multiple Initialisation
(function($) {
$.fn.myWidget = function(options) {
return this.each(function() {
var $el = $(this);
// Skip if already initialised
if ($el.data("myWidget-init")) return;
$el.data("myWidget-init", true);
// Run plugin logic once
$el.css("border", "2px solid blue");
});
};
})(jQuery);
Quick Summary
- Add methods to
$.fnto extend jQuery:$.fn.myPlugin = function() { ... }. - Wrap everything in
(function($) { ... })(jQuery)to safely use$. - Use
this.each()to handle multiple matched elements and return it for chaining. - Accept an
optionsargument and merge with defaults using$.extend(). - Support callbacks, prevent double-init with
$.data(), and prefix plugin names to avoid conflicts.
