← Back to jQuery Course | Chapter 14: Custom Plugins | Lesson 4 of 4

Plugin Best Practices

Plugin names should be specific and easy to understand. Avoid names that can conflict with other plugins.
Syntax
javascript
$.fn.pluginName = function(options) {
  var settings = $.extend({option: defaultValue}, options);
  return this.each(function() {
    // work on $(this) using settings
  });
};

Use Clear Names

A well-named plugin avoids generic, easily-collided names like init or update, and instead uses a name specific enough to describe what it actually does, such as imageCarousel rather than just carousel. Specific names reduce the chance of silently overwriting another plugin with the same name.

Example: Use Clear Names

javascript
<!DOCTYPE html>
<html>
<head>
  <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
    <style>
    .carousel-active { border: 2px solid blue; }
    </style>
  <style>
    button { padding:6px 14px; margin:4px; background:#2c6aa0; color:white; border:none; border-radius:4px; cursor:pointer; }
    #resetBtn { background:white; color:#2c6aa0; border:1px solid #2c6aa0; }
    #output { margin-top:10px; padding:8px; border:1px solid #ccc; border-radius:4px; background:#f7f7f7; font-family:monospace; min-height:24px; }
    #demo :where(p, div, span, li, h1, h2, h3, h4, td, th, blockquote, label, section, article, aside) { border:1px solid #4a7fb5; background:#eaf2fb; padding:6px 10px; margin:4px 0; border-radius:4px; }
    #demo :where(ul, ol) { border:1px dashed #888; background:#fafafa; padding:8px 8px 8px 32px; margin:6px 0; }
    #demo :where(table) { border-collapse:collapse; }
    #demo :where(td, th) { border-radius:0; }
    #demo :where(input, select, textarea) { margin:4px 0; }
  </style>
</head>
<body>
  <button id="runBtn">Run</button>
  <button id="resetBtn">Reset</button>
  <section id="demo">
    <div class="carousel">Slide</div>

  </section>
  <div id="output"></div>
  <script>
    var original = $("#demo").html();

    $("#runBtn").click(function() {
      $.fn.imageCarousel = function() {
        return this.addClass("carousel-active");
      };
      $(".carousel").imageCarousel();
    });

    $("#resetBtn").click(function() {
      $("#demo").html(original);
      $("#output").empty();
    });
  </script>
</body>
</html>

Keep Plugins Chainable

Return this from a plugin whenever it operates on the selected elements, since that's what allows other jQuery methods to be chained onto the call afterward. This matches the behavior jQuery's own built-in methods provide and is what users expect from any well-behaved plugin.

Example: Keep Plugins Chainable

javascript
<!DOCTYPE html>
<html>
  <head>
    <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
      <style>
      .box { background: steelblue; color: white; padding: 10px; border-radius: 4px; }
    </style>
  </head>
  <body>
    <div class="box" style="display:none">Box</div>
    <button id="btn">Run Plugin</button>
    <button id="resetBtn">Reset</button>
    <div id="output"></div>
    <script>
      $.fn.myPlugin = function() {
        return this.css("color", "gold");
      };
      $("#btn").on("click", function() {
        $(".box").myPlugin().fadeIn();
        $("#output").text("Plugin returned the jQuery object, so fadeIn() could be chained");
      });
      $("#resetBtn").on("click", function() {
        $(".box").stop(true, true).hide().css("color", "white");
        $("#output").text("");
      });
    </script>
  </body>
</html>

Use Defaults and Options

Always provide sensible default values for a plugin's options, and merge the caller's supplied options with those defaults — typically using $.extend() — so users only need to specify the settings they actually want to change, leaving everything else to work out of the box.

Example: Use Defaults and Options

javascript
<!DOCTYPE html>
<html>
  <head>
    <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
      <style>
      .box { background: steelblue; color: white; padding: 10px; border-radius: 4px; }
    </style>
  </head>
  <body>
    <div class="box" style="display:none">Box</div>
    <button id="btn">Run Plugin</button>
    <button id="resetBtn">Reset</button>
    <div id="output"></div>
    <script>
      $.fn.myPlugin = function(options) {
        const settings = $.extend({speed: 300}, options);
        return this.fadeIn(settings.speed);
      };
      $("#btn").on("click", function() {
        $(".box").myPlugin();
        $("#output").text("Faded in using the default speed of 300ms");
      });
      $("#resetBtn").on("click", function() {
        $(".box").stop(true, true).hide();
        $("#output").text("");
      });
    </script>
  </body>
</html>

Protect Scope and Avoid Conflicts

Use a closure to keep a plugin's internal helper variables private, and give the plugin itself a genuinely unique name, since both practices reduce the chance of conflicting with other scripts or plugins loaded on the same page.

Example: Protect Scope and Avoid Conflicts

javascript
<!DOCTYPE html>
<html>
<head>
  <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
  <style>
    body { font-family: sans-serif; padding: 12px; }
    button { padding:6px 14px; margin:4px; background:#2c6aa0; color:white; border:none; border-radius:4px; cursor:pointer; }
    button.secondary, #resetBtn { background:white; color:#2c6aa0; border:1px solid #2c6aa0; }
    input[type=text] { padding: 6px 8px; margin: 0 6px 8px 0; border: 1px solid #888; border-radius: 4px; font: 14px sans-serif; }
    .stage { border: 2px dashed #888; border-radius: 4px; padding: 10px; margin: 8px 0; min-height: 40px; background: #fafafa; }
    .stage::before { content: attr(data-label); display: block; font-size: 12px; color: #666; margin-bottom: 6px; }
    .item { border: 1px solid #4a7fb5; background: #eaf2fb; padding: 6px 10px; margin: 4px 0; border-radius: 4px; }
    .fresh { background: #ffe066 !important; border-color: #d4a600 !important; }
    .done { text-decoration: line-through; color: #a33; }
    ul.stage { padding-left: 32px; }
    ul.stage:empty::after { content: "(empty)"; color: #999; }
    ul.stage > li { border: 1px solid #4a7fb5; background: #eaf2fb; padding: 6px 10px; margin: 4px 0; border-radius: 4px; }
    .box { border: 2px solid #4a7fb5; background: #f3f8fd; border-radius: 4px; padding: 8px 10px; margin: 8px 0; min-height: 54px; }
    .box .label { display: block; font-weight: bold; margin-bottom: 6px; color: #2c6aa0; }
    #output { margin-top:10px; padding:8px; border:1px solid #ccc; border-radius:4px; background:#f7f7f7; font-family:monospace; min-height:24px; white-space:pre-wrap; }
    #output:empty::before { content: "Output appears here"; color: #888; }
  </style>
</head>
<body>
  <button id="runBtn">Run Plugin</button><button id="resetBtn" class="secondary">Reset</button>
  <p id="target" class="item">Plugin target</p>
  <div id="output"></div>
  <script>
    (function ($) {
      $.fn.uniquePluginName = function () {
        return this.css("color", "green");
      };
    })(jQuery);
    $("#runBtn").click(function () {
      $("#target").uniquePluginName();
      $("#output").text("uniquePluginName() ran inside an IIFE that receives jQuery as $, so $ can't conflict with other libraries");
    });
    $("#resetBtn").click(function () {
      $("#target").css("color", "");
      $("#output").text("");
    });
  </script>
</body>
</html>

Validate and Document

A trustworthy plugin validates its inputs rather than assuming they're always correct, and it documents its options and expected usage clearly. Simple validation — checking that a required option was actually provided, for example — can prevent confusing failures further down the line.

Example: Validate and Document

javascript
<!DOCTYPE html>
<html>
<head>
  <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
  <style>
    button { padding:6px 14px; margin:4px; background:#2c6aa0; color:white; border:none; border-radius:4px; cursor:pointer; }
    #resetBtn { background:white; color:#2c6aa0; border:1px solid #2c6aa0; }
    #output { margin-top:10px; padding:8px; border:1px solid #ccc; border-radius:4px; background:#f7f7f7; font-family:monospace; min-height:24px; }
    #demo :where(p, div, span, li, h1, h2, h3, h4, td, th, blockquote, label, section, article, aside) { border:1px solid #4a7fb5; background:#eaf2fb; padding:6px 10px; margin:4px 0; border-radius:4px; }
    #demo :where(ul, ol) { border:1px dashed #888; background:#fafafa; padding:8px 8px 8px 32px; margin:6px 0; }
    #demo :where(table) { border-collapse:collapse; }
    #demo :where(td, th) { border-radius:0; }
    #demo :where(input, select, textarea) { margin:4px 0; }
  </style>
</head>
<body>
  <button id="runBtn">Run</button>
  <button id="resetBtn">Reset</button>
  <section id="demo">
    <div class="box">Box</div>

  </section>
  <div id="output"></div>
  <script>
    var original = $("#demo").html();

    $("#runBtn").click(function() {
      $.fn.myPlugin = function(options) {
        if (!options || !options.color) {
          $("#output").text("myPlugin requires a color option");
          return this;
        }
        return this.css("color", options.color);
      };
      $(".box").myPlugin({color: "red"});
    });

    $("#resetBtn").click(function() {
      $("#demo").html(original);
      $("#output").empty();
    });
  </script>
</body>
</html>
Related Topics
{# common_mistakes/chapter_summary/browser_support: on Hindi pages the view already swaps in the hi_ translation fields (or blanks these out if untranslated), so this renders correctly for both languages without a lang_code check here. #}
Common Mistakes
  1. Naming a plugin something generic like $.fn.init or $.fn.update, which collides with existing methods.
  2. Storing state in a shared variable outside each(), so multiple elements overwrite each other's settings.
  3. Mutating the shared defaults object with $.extend(defaults, options), when it should be $.extend({}, defaults, options).
Chapter Summary
  • Existing plugins can be integrated into a page.
  • The jQuery prototype chain is how plugins add new methods.
  • Authoring a custom plugin follows best practices for reusable code.
🔒

Chapter Quiz — Complete all 4 topics to unlock

0/4 topics done

Complete these topics first:

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.