Creating Zepto Plugins from jQuery Plugins

Recently you may have noticed I migrated a few plugins to also be Zepto compatible. Most notably Waiting, Litelighter, and Powertable. For the most part jQuery and Zepto have a highly compatible api, however there are some differences. I'd like to note a few of the major differences I noticed while converting these plugins.


This doesn't exist in Zepto the way it does in jQuery. However, unless you're creating a lot of methods off of $(), you don't really need to use it. For example with Waiting I only needed $().waiting(), so there is no need to use extend. This is likely the case with most plugins.

$.fn.waiting = function(options){
    // plugin code in here..

Detecting jQuery or Zepto

At first this may seem tricky, but it is not. You should be wrapping you code like this already:

    // code...

Well guess what, if jQuery isn't defined, just use Zepto!

    // code...
})(window.jQuery || window.Zepto || window.$);

What happens here is the first that is defined will be passed as the parameter.

Event Binding

Zepto does mention that .bind() is deprecated and .on() is the preferred method. I like .on() better personally since you can do direct events and delegate all in one.

Custom Event Namespacing

You can namespace your events, but unlike jQuery where it allows you to use "click.MyNamespace" and "customEvent.MyNamespace". Zepto seems to only like the colon syntax for custom events, which looks like "MyNamespace:customEvent". However Zepto prefers the "click.MyNamespace" for native events. So in the Waiting plugin the custom event for "enable" looks like this:


Pseudo Selectors

Pseudo selectors are limited. If you've been making use of complex selectors or helpers like ":visible" it is likely they probably won't work. It is likely easy to work around, just think ahead. The Zepto documentation even mentions there is a "selector" module that can be used for a few of the more common selectors.

Data Attributes

With jQuery I would store the plugin instance in a data attribute, and at any time I could retrieve the instance via $('.selector').data('waiting'). However Zepto only works with simple data types. There is an optional data module you can include. I opted for an alternative route which is super simple. Create a lookup object, and only store the key in the data. What do I mean by this?

// i is simply a counter, the rest 
// of what is stored will be instances
$.waiting.lookup = {
    i: 0

// store the new instance.. $t=$(this)
$.waiting.lookup[++$.waiting.lookup.i] = new $.waiting($t, o);
$'waiting', $.waiting.lookup.i);

// retrieve the instance
var inst = $.waiting.lookup[$(this).data('waiting')];

You can see I just increment the $.waiting.lookup.i to always have a unique key. From there it is just accessing that instance in the lookup. Not to bad of work around to prevent loading a separate module.


This was an odd issue I found, and I was perhaps using incorrectly from the start (intentionally). serializeArray works best on a form element, whereas jQuery doesn't really mind what you call it on. The fix? Use it on a form. If you don't want the form to submit just stop the event on submit.

outerWidth and outerHeight

outerWidth and outerHeight are not available in Zepto, but are easy to work around. You can either implement your own by adding the width + padding + border, or simply set the css attribute box-sizing: border-box and then use Zepto's width()/height() method.

Final Thoughts

A few of my plugins where a matter of 10 minutes to make Zepto compatible. I was more than happy to make those changes. However a few plugins of mine were much more complex and maybe they're not good candidates for the conversion since they rely too heavily on Zepto's compatibility.

I found that much of the more compatible plugins where those where I wrote more native javascript instead of being lazy and using jQuery. In fact there is no way Powertable would be possible entirely with jQuery to manipulate tables with thousands of rows, it created to much overhead.(and thats another topic in itself) I also used pure javascript with the animation in Waiting, so I didn't need complex selectors.