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 (or this.each()) for chainability.
  • Use $.extend({}, defaults, options) to merge settings without modifying defaults.
  • Prefix your plugin name to avoid conflicts: $.fn.myappSlider not $.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 $.fn to 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 options argument and merge with defaults using $.extend().
  • Support callbacks, prevent double-init with $.data(), and prefix plugin names to avoid conflicts.

Leave a Comment

Your email address will not be published. Required fields are marked *