How to Create a jQuery Bookmarklet

I suspect many of my readers have written at least one jQuery Plugin / Script. In this post, I’d like to show you how to get the most out of that script by also releasing it as a jQuery Bookmarklet. Below, you’ll find two examples of utilities that are ripe for bookmarkleting, as well as a prepared jQuery Bookmarklet file that you can easily modify for the purpose.

Note: Even if you haven’t written a jQuery plugin before, you’ll find bookmarkleting someone else’s plugin as easy as using it on a site.

Before I get to the code though – take a look at the payload. You can add the following links as bookmarklets by right-clicking and selecting “Add to bookmarks / favorites” (in Chrome, you press “ctrl+shift+b” to open the bookmark manager, and drag them over). You can try them before you bookmark them by simply clicking the links on this page too.

Example One:


Clicking the above link will add the table sorter jquery plugin to the page, including its stylesheet, and it will apply the script to all tables on the page. Once it’s loaded, you can click on any of the table column headers to sort the rows by column values.

Example Two:

The visualizer bookmarklet will add graphical representations of the data in the table. As with the table sorter, this bookmarklet was adapted from a pre-existing plugin, Filament’s jQuery Visualize.

2009 Employee Sales by Department
food auto household furniture kitchen bath
Mary 190 160 40 120 30 70
Tom 3 40 30 45 35 49
Brad 10 180 10 85 25 79
Kate 40 80 90 25 15 119

Cool stuff, right? Let’s get to how it works then – starting with the prepared jQuery Bookmarklet template. This is what I recommend you use when writing your own bookmarklets:

/*
 * jQuery Bookmarklet - version 1.0
 * Originally written by: Brett Barros
 * With modifications by: Paul Irish
 *
 * If you use this script, please link back to the source
 *
 * Copyright (c) 2010 Latent Motion (http://latentmotion.com/how-to-create-a-jquery-bookmarklet/)
 * Released under the Creative Commons Attribution 3.0 Unported License,
 * as defined here: http://creativecommons.org/licenses/by/3.0/
 *
 */
 
window.bookmarklet = function(opts){fullFunc(opts)};
 
// These are the styles, scripts and callbacks we include in our bookmarklet:
window.bookmarklet({
 
    css : ['http://www.site.com/your.css'],
    js  : ['http://www.site.com/your.js'],    
//	jqpath : 'myCustomjQueryPath.js', <-- option to include your own path to jquery
    ready : function(){
 
		// The meat of your jQuery code goes here
		$("body").html("Hello World");
 
   	    }
})
 
function fullFunc(a){function d(b){if(b.length===0){a.ready();return false}$.getScript(b[0],function(){d(b.slice(1))})}function e(b){$.each(b,function(c,f){$("<link>").attr({href:f,rel:"stylesheet"}).appendTo("head")})}a.jqpath=a.jqpath||"http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js";(function(b){var c=document.createElement("script");c.type="text/javascript";c.src=b;c.onload=function(){e(a.css);d(a.js)};document.body.appendChild(c)})(a.jqpath)};

From top to bottom, what the jQuery Bookmarklet Template does is:

  1. Prepare the full bookmarklet function. This is the call to the minified code in the last line of the js file. It is in an uncompressed format at the bottom of this post for those interested, but most will never need to see it..
  2. Create the configurations, including arrays to your CSS and JS files. You can load as many as you see fit, and the JS files will load asynchronously, ensuring that each file can reliably depend on the file before it.
  3. Provides the callback function for your editing. Place whatever jQuery code you like here.

In order to use that script, though, you’ll need to create a link that calls it. Here’s the code for that link:

<a href="javascript:(function(){var head=document.getElementsByTagName('head')[0],script=document.createElement('script');script.type='text/javascript';script.src='http://www.site.com/your-javascript.js?' + Math.floor(Math.random()*99999);head.appendChild(script);})(); void 0">Your Bookmarklet Name</a>

To some that might look like a handful, but don’t worry, the hard work is already done. All you need to do is change the url in that link to point to your javascript file, and add a little regular-ol-jQuery to that javascript file.

Ok, still with me? Great! Now let’s look at one of the actual live examples we used earlier on the page. Here’s how I included table sorter, which requires both a JS and CSS file:

/*
 * jQuery Bookmarklet - version 1.0
 * Originally written by: Brett Barros
 * With modifications by: Paul Irish
 *
 * If you use this script, please link back to the source
 *
 * Copyright (c) 2010 Latent Motion (http://latentmotion.com/how-to-create-a-jquery-bookmarklet/)
 * Released under the Creative Commons Attribution 3.0 Unported License,
 * as defined here: http://creativecommons.org/licenses/by/3.0/
 *
 */
 
window.bookmarklet = function(opts){fullFunc(opts)};
 
// These are the styles, scripts and callbacks we include in our bookmarklet:
window.bookmarklet({
 
    css : ['http://tablesorter.com/themes/blue/style.css'],
    js  : ['http://tablesorter.com/jquery.tablesorter.js'],    
//	jqpath : 'myCustomjQueryPath.js', <-- option to include your own path to jquery
    ready : function(){
 
		// Initiate table sorter
		$("table").tablesorter().addClass("tablesorter"); 	
 
   	    }
 
})
 
function fullFunc(a){function d(b){if(b.length===0){a.ready();return false}$.getScript(b[0],function(){d(b.slice(1))})}function e(b){$.each(b,function(c,f){$("<link>").attr({href:f,rel:"stylesheet"}).appendTo("head")})}a.jqpath=a.jqpath||"http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js";(function(b){var c=document.createElement("script");c.type="text/javascript";c.src=b;c.onload=function(){e(a.css);d(a.js)};document.body.appendChild(c)})(a.jqpath)};

For your convenience, you can also download the script as a JS file.

And that’s about it! Sorta, anyway. Here’re some bonus thoughts for the real enthusiasts:

  1. Bookmarklets leverage caching, big time. When developing, I found this to be a major frustration, so I added a large random number at the end of the js call, which effectively forces a reload each time the javascript is called. Upon deployment – you may choose to remove it, but keep it in mind next time you make a change and don’t see the effects.
  2. Another reason I force refreshing of my js file is because I want to be able to update my scripts without forcing my users to re-bookmark them.
  3. If you create your own bookmarklet and want to post about it in wordpress, you’ll quickly learn you need a workaround. The first one I used was hardcoding the links in an external page, and displaying them through an iframe. It worked, but was lame. Now I’m using javascript to store the desired a href as a variable, then I wrap that variable with the tags, and finally I document.write it. If you have a better idea, let me know.
  4. The table examples that I’ve provided on this page are based on pre-existing jQuery plugins. Those plugins assume that tables are correctly formatted, with table headers etc. If a website’s layout was built in the 90s and still uses tables for page structure, the results won’t be pretty.
  5. Sadly, Disqus (the host service for my comments below) uses tables. This of course conflicts with the specific table examples I used above, and can be resolved by refreshing. I’m sure it’s possible to set the bookmarklet to listen for a click of a table, but that’s beyond the scope of the current script/lesson.

And here’s some extra credit reading:

  • Learning jQuery made me realize that loading jQuery dynamically is possible. Almost ironically, Paul Irish helped with some modifications over there too.
  • After writing this article, I was informed Ben Alman had already written a similar script. His actually includes a “generator” that will use your jquery code and embed it for you, which is cool. It doesn’t include a loop to first include javascript / css files, but he probably figured it was easy enough to add yourself.
  • Tommy, at Smashing Magazine, wrote a much more in-depth article about the details and options when writing a jQuery bookmarklet. Although it was posted a few days after I posted mine, he had submitted it months in advance. Smart guy ;)
  • Marklets is a pretty nifty bookmark database that gives you searchable access to triggering any script in the arsenal. The creator and I are discussing a joint bookmarkleting project. Contact me if you’re interested in making bookmarklets kick ass again.

If you have any ideas, questions, or musings, I’d love to hear ‘em! Please add your comment below.

Update: Paul Irish was kind enough to help improve this script and teach me a couple things along the way. The following is the unminified version of what I’ve listed above, and includes his structural changes.

/*
 * jQuery Bookmarklet - version 1.0
 * Originally written by: Brett Barros
 * Heavily modified by: Paul Irish
 *
 * If you use this script, please link back to the source
 *
 * Copyright (c) 2010 Latent Motion (http://latentmotion.com/how-to-create-a-jquery-bookmarklet/)
 * Released under the Creative Commons Attribution 3.0 Unported License,
 * as defined here: http://creativecommons.org/licenses/by/3.0/
 *
 */
 
window.bookmarklet = function(opts){fullFunc(opts)};
 
// These are the styles, scripts and callbacks we include in our bookmarklet:
window.bookmarklet({
 
    css : ['http://tablesorter.com/themes/blue/style.css'],
    js  : ['http://tablesorter.com/jquery.tablesorter.js'],    
//	jqpath : 'myCustomjQueryPath.js', <-- option to include your own jquery
    ready : function(){
 
		// Initiate table sorter
		$("table").tablesorter().addClass("tablesorter"); 	
 
   	    }
 
})
 
function fullFunc(opts){
 
    // User doesn't have to set jquery, we have a default.
    opts.jqpath = opts.jqpath || "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js";
 
    function getJS(jsfiles){
 
	// Check if we've processed all of the JS files (or if there are none)
	if (jsfiles.length === 0) {
		opts.ready();
		return false;
	}
 
        // Load the first js file in the array
        $.getScript(jsfiles[0],  function(){ 
 
            // When it's done loading, remove it from the queue and call the function again    
            getJS(jsfiles.slice(1));
 
        })
 
    }
 
    // Synchronous loop for css files
    function getCSS(csfiles){
        $.each(csfiles, function(i, val){
            $('<link>').attr({
                    href: val,
                    rel: 'stylesheet'
                }).appendTo('head');
        });
    }
 
	function getjQuery(filename) {
 
		// Create jQuery script element
		var fileref = document.createElement('script')
		fileref.type = 'text/javascript';
		fileref.src =  filename;
 
		// Once loaded, trigger other scripts and styles
		fileref.onload = function(){
 
			getCSS(opts.css); // load CSS files
			getJS(opts.js); // load JS files
 
		};
 
		document.body.appendChild(fileref);
	}
 
	getjQuery(opts.jqpath); // kick it off
 
}; // end of bookmarklet();
  • Digg
  • Sphinn
  • del.icio.us
  • RSS

Popular Posts

Alternatively, you may want to return to the Home Page to view the most recent blog posts in order. If you have any questions, I make a point of reading and responding to all comments. Thanks for joining!

  • Celeste
    This is really neat! I've been trying it out in Firefox, but for some reason none of the bookmarklets above work in IE7, and neither does the one I've created.

    Any thoughts? (This is a *very* useful tutorial, btw! :))
  • Great work. Thank you!!
    Inspired in this idea, i've created a framework to build bookmarklets easily and you can choose use jquery or not. You can check it here: http://idc.anavallasuiza.com/bookmarklets/
  • Craig Lebowitz
    Great tutorial... I especially like the _bonus thoughts for enthusiasts_!
  • Tom
    Any thoughts on how to reset the bookmarklets css so it looks the same on all websites and browsers? One thing I've had issues with is the bookmarklet will inherit css from the site it's loaded on. It would be cool to include some css file that clears/resets all that. Any thoughts?
  • Good question. This goes beyond bookmarklets even - and into the broader reaches of plugins. How can a plugin secure itself against unwanted css (or even external javascript event collision!)?

    And it also begs the question of what exactly do we want to reset to? Something like yahoo's reset css? Or to the browser's defaults? Can we universalize the browser defaults, or do we have to use javascript to create a page in an iframe (thus unstyled), and get all of the properties of the elements that way?

    My inclination would be to go the yahoo reset route, and just be aware of what exactly we're resetting to before implementing our own styles. As far as I can imagine, we've got to use !important;, and then have our own styles override that same !important; by selector specificity and/or code order...

    Something like:
    #myDiv, #myDiv * {float:none !important; clear:both !important; font-size:10px !important;} /* a bunch of reset css */
    #myDiv li { font-size:12px !important; } /* a bunch of custom css */

    That about sums up my thoughts. Anyone else?
  • Tom
    I was hoping there would be a more graceful solution. Looks like using the bookmarklets container id as the selector and defining every css property with the default value would be a good start. I don't think it will be necessary to use the '!important' tag, it is only used to win out over contradictory styles with selectors of equal weight but using the id as the selector should have the highest weight. You can read more detail on that here:
    http://www.w3.org/TR/css3-selectors/#specificity

    I'll try using this list to get all the css properties redefined to their defaults.
    http://www.w3.org/TR/CSS2/propidx.html

    The css looks something like:

    NOTE: THIS IS NOT TESTED

    #mainContainer
    {
    azimuth: center;
    background: transparent none repeat scroll 0% 0%;
    border: medium none transparent;
    bottom: auto;
    caption-side: top;
    clear: none;
    clip: auto;
    color: depends on user agent;
    content: normal;
    counter-increment: none;
    counter-reset: none;
    cue: none none;
    cursor: auto;
    direction: ltr;
    display: inline;
    elevation: level;
    empty-cells: show;
    float: none;
    font-family: depends on user agent;
    font-size: medium;
    font-style: normal;
    font-variant: normal;
    font-weight: normal;
    font: Arial,Helvetica,sans-serif;
    height: auto;
    left: auto;
    letter-spacing: normal;
    line-height: normal;
    list-style: disc outside none;
    margin: 0;
    max-height: none;
    max-width: none;
    min-height: 0;
    min-width: 0;
    orphans: 2;
    outline: invert none medium;
    overflow: visible;
    padding: 0;
    page-break-after: auto;
    page-break-before: auto;
    page-break-inside: auto;
    pause-after: 0;
    pause-before: 0;
    pitch-range: 50;
    pitch: medium;
    play-during: auto;
    position: static;
    quotes: none;
    richness: 50;
    right: auto;
    speak-header: once;
    speak-numeral: continuous;
    speak-punctuation: none;
    speak: normal;
    speech-rate: medium;
    stress: 50;
    table-layout: auto;
    text-align: left;
    text-decoration: none;
    text-indent: 0;
    text-transform: none;
    top: auto;
    unicode-bidi: normal;
    vertical-align: baseline;
    visibility: visible;
    voice-family: announcer, male;
    volume: medium;
    white-space: normal;
    widows: 2;
    width: auto;
    word-spacing: normal;
    z-index: auto;
    }
  • #otherContainer .roar {font-size:30px;} would win out against an id-only selector. Specificity stacks with additional selectors, so I think that doing important might actually be necessary.
  • Nice, that's exactly the kind of code I had in mind, thanks for sharing. He's got a pretty extensive list of styles covered there :)
  • Thanks for the plug, sorry for the confusion, etc!
  • Likewise. You're a cool cat =)
  • I've also created a bookmarklet generator that allows you to run some arbitrary code that requires jQuery, loading a minimum required version of jQuery first (but only if necessary), affecting the host page as little as possible.

    It's useful for bookmarklets that need jQuery to execute their payload, in situations where you don’t know if jQuery or a specific minimum required version of jQuery will already exist in the page.

    http://benalman.com/projects/run-jquery-code-bookmarklet/
  • I've also created a bookmarklet generator! :)
    It is inspired by your one, but with some additional features: code minifing, maximum jQuery version, easy re-editing by using bookmarklet on an blank page.

    http://bender.fesb.hr/~robert/jquery-bookmarklet-generator/
  • Kudos. Credit has been added to the post.
  • Mads Jensen
    FYI - the link for jQuery Visualize is wrong.

    Great stuff, thanks!
  • Oops! It's fixed now, thanks :)
  • Tom
    Nice tutorial. I think it might be the best I've seen.

    I'm the developer of http://www.marklets.com (the bookmarklet directory) and will add a link to this post on my FAQ page. Nice work!
  • Hey Tom, thanks for posting! Your bookmarklets database is fantastic. In fact, I was going to build something just like it as my next project, but I think you've already got it covered.

    In addition to being able to search to use a bookmarklet, it would be nice if people could save specific ones as favorites, and locate them in a drop down menu. Hit me up if you want to brainstorm on how to do this together.
  • Nice tutorial. I've created some bookmarklets in raw javascript, but this tutorial is more expanded than what i've done. Thanks for sharing.
  • This is exactly what I was searching for these days! I can't believe I found this article!
    Great tutorial - explained well and with good examples. Thanks!
  • Glad I could help! If you've got a site you're going to use it on,
    please do me the courtesy of linking back here =)
blog comments powered by Disqus