Building jQuery plugins

A jQuery plugin is simply a way to put your code into a package. It makes it easier to maintain and use in different projects. Before you read this article it’s recommended that you’re familiar with how jQuery works.

Basic Structure

In case you want to share your plugin with others it can be a good idea to stick to the conventions of plugin authoring. Pick a suitable name like “myPlugin” and name your file jquery.myPlugin.js. Next thing is to define a function body.

(function($) {
    $.fn.extend({
        myPlugin: function() {
        }
    });
})(jQuery);

Wrapping everything inside an anonymous function and passing jQuery into it makes sure it doesn’t conflict with other libraries that uses ‘$’ as a shorthand (Don’t worry too much about this for now).

jQuery.tabify

I’m going to call the first plugin “tabify”. The objective is to add some tabs to the following content.

<div id= someContent >
    <h2>Tab number one</h2>

    <div>
        <p>Some tab content</p>
    </div>
    <h2>Next tab</h2>
    <div>

        <p>content...</p>
    </div>
    <h2>Last tab</h2>
    <div>
        <p>Even more stuff</p>

    </div>
</div>

Inside your plugin add the following:

return this.each(function() {
    var obj = $(this);
});

An object passed through the plugin will now return a function. I also created a reference “obj” to the object currently inside the function. Add the following inside your “this.each” statement:

obj.click(function() {
    obj.css({ backgroundColor:&quot;red&quot;});
});

Now pass the desired object into the plugin:

$(function(){{
    $('#someContent').tabify();
});

Clicking #someContent should result in a red background. You could pass any object into the plugin. $(‘#someContent h2’) will set a red background to any “h2” within #someContent that is clicked.

Tabifying your content

Here’s the code for jquery.tabify with included comments. I’m hoping you’re fairly familiar with JavaScript / jQuery and its basic syntax.

(function($){
    $.fn.extend({
        tabify: function() {

            return this.each(function() {

                //Creating a reference to the object
                var obj = $(this);

                /* Create a reference for all headings and
                its content using .next().
                Remember to pass the object reference
                 obj  into the identifier. */

                var headings = $( 'h2 ', obj);
                var tabContent = headings.next();

                //We wan 't to hide the headings and the content
                headings.hide();
                tabContent.hide();
                /* But we want to show content of the first
                tab since it 's selected by default. */
                tabContent.eq(0).show();

                //Prepend the object with the tab container (ul).
                obj.prepend( '<ul class= tabs ></ul> ');

                //For every heading create an item (<li>)
                headings.each(function() {

                    var label = $(this).text();
                    $( ul.tabs , obj).append( <li>  + label +  </li> );
                });
                var tabs = $( ul.tabs li , obj);

                //And add .sel class to first item
                tabs.eq(0).addClass( sel );

                //Create a reference to the tabs for each obj
                var tabs = $( ul.tabs li , obj);

                tabs.click(function() {

                    //When a tab is clicked  de-activate  the old one
                    tabs.removeClass( sel );
                    tabContent.hide();
                    $(this).addClass( sel );

                    //And display the clicked tab
                    var current = tabs.index($(this));
                    tabContent.eq(current).show();
                });
            });
        }
    });
})(jQuery);

</code></pre>

<p>
You will also need some CSS to actually make your <ul> look like tabs.
</p>

<div class=&quot;article-demo&quot;>
<h2>jQuery.tabify Demo</h2>
<div id=&quot;tabify&quot;>
    <h2>Tab number one</h2>
    <div>

        <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. </p>
<p>
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. </p>
        </div>
    <h2>Next tab</h2>
    <div>
        <p>Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. </p>
    </div>

    <h2>Last tab</h2>
    <div>
        <p>Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
    </div>
</div>
</div>

<h2>Modularity</h2>

<p>
Now we have a nice unobtrusive jQuery plugin ready for usage. However it does have a few drawbacks.
</p>

<ul>
<li>It’s not flexible at all. It’s requires using “h2” in the markup. What if someone wanted to use an “h3” or “h4” they’d have to hack the plugin? (Yes I know there is a :header filter but let’s pretend there isn’t :P  )</li>
<li>The tabs will always have the class “tabs”. What if there is already a “tabs” class in use on a client page?</li>
</ul>

<p>
So what can we do about this? It’s actually very simple. We can let our plugin be customizable from the outside by using the jQuery.extend method. This is what we will do in our next plugin.</p>

<h2>jQuery.lessMore</h2>

<p>
This plugin will have a more flexible design. Our goal is to be able to hide any given number of child elements from a given parent. We build the plugin body like before but this time we pass the “options” variable into the plugin function.
</p>

[code lang=&quot;js&quot;](function($) {
    $.fn.extend({
        lessMore: function(options) {
        }
    });
})(jQuery);

Now we can start with adding a set of default options to the plugin

var defaults = {
    limit: 3,
    moreText: &quot;More&quot;,
    lessText: &quot;Less&quot;,
    numbers: true,
    append: true,
    moreClass: &quot;more&quot;,
    lessClass: &quot;less&quot;
};
var options = $.extend(defaults, options);

And by using extend method a user can now override the defaults when initializing the plugin.

$('#content').lessMore({
    limit: 5,
    numbers: false
});

Notice I chose only to override two of the defaults here.
Some more code: lessMore
Again I won’t go into details here but this plugin simply illustrates the use of user defined options and plugin defaults.

(function($){
    $.fn.extend({
        lessMore: function(options) {

            var defaults = {
                limit: 3,
                moreText:  More ,
                lessText:  Less ,
                numbers: true,
                append: true,
                moreClass:  more ,
                lessClass:  less 

            };

            var options = $.extend(defaults, options);

            return this.each(function() {

                var obj = $(this);

                //Create references to the options
                var moreClass = options.moreClass
                var lessClass = options.lessClass
                var lessText = options.lessText;
                var moreText = options.moreText;

                //Calculate number of rows and hide them
                var rows = obj.children();
                var quantity = rows.length - options.limit;
                rows.slice(options.limit).hide();

                //If  numbers  is set to true append with number of items hidden
                if(options.numbers) {
                    moreText +=  ' ( ' + quantity +  ') ';
                }

                //Only add the link if quantity of child elements exceeds the options.limit
                if(quantity > 0) {
                    var control =  '<span class=  '+ moreClass + ' > '+ moreText + '</span> ';
                }

                //Check if  append  is set to true, otherwise prepend the  control 

                if(options.append) {
                    obj.append(control);
                }
                else {
                    obj.prepend(control);
                }

                //Create a reference to the control

                var itemControl = $( '. ' + moreClass, obj);

                itemControl.click(function() {

                    var link = $(this);
                    var linkif = link.hasClass(moreClass);

                    // If rows are hidden, show them, and change our link.

                    if (linkif) {
                        link.removeClass(moreClass);
                        link.addClass(lessClass);
                        link.html(lessText);
                        rows.slice(options.limit).show();
                    }
                    else {
                        link.removeClass(lessClass);
                        link.addClass(moreClass);
                        link.html(moreText);
                        rows.slice(options.limit).hide();
                    }
                });
            });
        }
    });
})(jQuery);

Hopefully you now know the basics of building a simple jQuery plugin.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Facebook
  • Live
  • Google Bookmarks
  • BlinkList
  • FriendFeed
  • Ping.fm
  • StumbleUpon
  • Technorati
  • Mixx
  • Reddit
  • Blogosphere News
  • Fark
  • Identi.ca
  • LinkedIn
  • Sphinn
  • TwitThis
  • E-mail this story to a friend!
  • Print this article!