Anatomy of a jQuery Plugin

Since released, jQuery has become one of the key components in web projects. Extensibility, easy to use, short learning curve and huge community support, makes it to be the first choice for a front-end developer most of the time.

Plugins in jQuery are reusable, they support different options through their methods with the attached objects. Basic jQuery plugin consists of a jQuery closure and a return command. We will look into the plugin anatomy with a sample textlimiting plugin. Lets dig-in details.

The Closure

;(function($){
    $.fn.textlimit = function(options){
        return this.each(function(){
            // plugin actions
        });
    };
})(jQuery);

* In plugins, starting with semicolon will make sure that the previous code closed properly and plugin code will not break in minification.

(function($){})(jQuery) part for the plugin is the jQuery closure. It auto adds your functions to jQuery scope. All the plugin code will and should reside in this closure. $.fn.textlimit is the name of your plugin. You can call your plugin as $("#el").textlimit. While attaching the plugin events to an object, returning itself is the magic for chainability. If you do not return the original object, chaining will be broken.

Inside the closure, you are free with your plugin architecture. For maintainability, break down your code into smaller methods and put them outside of the return part separately.

The Defaults and The Return

;(function($){
    var defaults = {
        maxlength: 0,
        counter: '.remaining'
    };

    $.fn.textlimit = function(options){
        return this.each(function(){
            var $el = $(this),
                textlimit;

            if($el.hasClass('textlimit-ready') return;

            $el.addClass('textlimit-ready');

            textlimit = new TextLimit($el, options);
        });
    };
})(jQuery);

Customizing the plugin helps to control over complexity of the plugin. Defining default values and accepting new values for these defaults are the easiest approaches to differentiate the plugin usage and for outputs across different objects. To do this, start with an object literal named like defaults, settings etc. with initial predefined values. Later, merge these default values with options accepted while attaching the plugin.

Inside the return, first cache the jQuery object. Then, just to be safe and not to attach the plugin multiple times to the object, check if the plugin is already attached. Adding a unique class like textlimit-ready or a similar class will make the job. This could be the simplest way to check it. After that, call the constructor method as in textlimit = new TextLimit($el, options); part.

The Constructor

var TextLimit = function($el, options){
    var opts = $.extend({}, defaults, options),
        $counter = $el.next(opts.counter),
        limit;

    limit = $el.attr('maxlength') ? parseInt($el.attr('maxlength')) : opts.maxlength;
    if(limit > 0) {
        $counter.text(limit);

        bindUIActions($el, limit, $counter);
    }
};

Constructor method of the plugin collects the options and binds the UI actions to the object. jQuery's extend function, merges the accepted options during the plugin call with default options to give new set of values. In the opts variable with opts =$.extend({}, defaults, options) line, we set these options for the current object. Then, check if there is proper limit defined for the text inputs.

The Extras

var bindUIActions = function($el, limit, $counter){
    // first count initial
    countChars($el, limit, $counter);

    $el.on('keyup', function(){
        return countChars($el, limit, $counter);
    });
};

var countChars = function($el, limit, $counter){
    var value = $el.val(),
        valLength = value.length,
        remaining = limit - valLength;

    if(remaining < 0){
        $el.val(value.substring(0, limit));
        remaining = 0;
    }

    $counter.text(remaining);
};

These parts of the plugin are to support "break down your code into smaller methods" argument that I mentioned above. bindUIActions binds the ui related actions to the object in a single method. The final countChars method calculates the char length in the input. Also, it checks if there is any available space for the next char and if the user reached the defined limit forbids adding new chars.

All Together

The following code block and the CodePen embed is the final version of the sample plugin and the working example.

;(function($){
    // default plugin options
    var defaults = {
        maxlength: 0,
        counter: '.remaining'
    };

    // Constructor method
    var TextLimit = function($el, options){
        var opts = $.extend({}, defaults, options),
            $counter = $el.next(opts.counter),
            limit;

        limit = $el.attr('maxlength') ? parseInt($el.attr('maxlength')) : opts.maxlength;
        if(limit > 0) {
            $counter.text(limit);

            bindUIActions($el, limit, $counter);
        }
    };

    // UI action bindings
    var bindUIActions = function($el, limit, $counter){
        // first count initial
        countChars($el, limit, $counter);

        $el.on('keyup', function(){
            return countChars($el, limit, $counter);
        });
    };

    // Counting the chars
    var countChars = function($el, limit, $counter){
        var value = $el.val(),
            valLength = value.length,
            remaining = limit - valLength;

        if(remaining < 0){
            $el.val(value.substring(0, limit));
            remaining = 0;
        }

        $counter.text(remaining);
    };

    $.fn.textlimit = function(options){
        return this.each(function(){
            var $el = $(this),
            textlimit;

            // if plugin is already attached to the element, do not attach again
            if($el.hasClass('textlimit-ready')) return;

            $el.addClass('textlimit-ready');

            // call the constructor method
            textlimit = new TextLimit($el, options);
        });
    }
})(jQuery);

See the Pen Larjg by Bilal Çınarlı (@bcinarli) on CodePen.

To sum up, a jQuery plugin is a new method or utility that will be available in your code. It is reusable, and it can support complex actions and operations.

Further reading