Bookmarklets are little plugins for your browsers: JavaScript programs packed into javascript: URLs that you add to your bookmarks and start by clicking on them. They perform an operation on the currently open web page such as submitting it to Twitter. There are even bookmarklets that transform the current web page, for example, to add icons that, when clicked, add an event to Google Calendar. A separate post explains what bookmarklets are in more detail. This post tells you how to implement bookmarklets. It presents techniques, tools, and patterns for doing so.

Preparation and techniques

helps you with trying out your JavaScript program in the same environment that the bookmark will eventually run in. Just go to an interesting website and run your code snippets in its shell. Its multi-line code editor is very helpful in this regard: To enable it, click the expansion button in the single-line console. Furthermore, Firebug lets you copy the current code to the clipboard, as a bookmarklet link. This link is crude, but it works. We’ll later see, how it can be made more compact.

Don’t pollute the global namespace: You don’t want to mess up the environment of the web site “in which” your bookmarklet is executed. For example, by using an Immediately Invoked Function Expression (IIFE) the variable t won’t become global, below.

(function() { var t=document.title; console.log("Title: "+t); }())

var

abc

(function() { t = "abc"; }()); console.log(t);

(function() { "use strict"; t = "abc"; }());

ReferenceError: assignment to undeclared variable t

If you switch on strict mode , JavaScript warns you about more potential problems. Later on, you can switch it off so that the bookmarklet URL is more compact, but for development, it is very helpful. For example, the code below inadvertently creates a global variable, because ahas been forgotten. The output isStrict mode, however warns you that there is a problem:Result:

Finish with undefined: If you don’t return (or finish with!) undefined , the result replaces the current web page. [Note: Webkit browsers such as Chrome and Safari never replace a page, only non-Webkit browsers such as Firefox do.]

Automatic if you use an IIFE: The result of a function is undefined unless you return something.

unless you return something. Chain of statements: Make undefined the last statement.

the last statement. Single expression: use the void operator to “mask” the result of an expression. It evaluates its operand and returns undefined . The first bookmarklet below replaces the current web page. The second one doesn’t. javascript:window.open("http://www.whitehouse.gov/") javascript:void window.open("http://www.whitehouse.gov/")

<script>

src

onload

<head>

onload

var d = document; var s = d.createElement('script'); s.src='https://ajax.googleapis.com/.../jquery.min.js'; s.onload = function() {...}; d.getElementsByTagName('head')[0].appendChild(s);

Collect input

The following code shows you how to load a script (with a library etc.). It creates aelement, adds the attributesandand inserts it directly after theelement. The insertion causes the script to load and once loading is finished, the function pointed to bywill be called.Caveat: A bookmarklet is subject to the same restrictions as the page on which it is executed. Thus, invoking a bookmarklet on an online page cannot load files from your local hard drive. This is unfortunate, because it would allow you to put most of the code of a bookmarklet into an (offline-accessible) separate file.This section describes how to collect input from the currently shown web page.

Parse HTML manually: Standard DOM provides several methods that let you retrieve HTML elements from the current page.

getElementsByClassName()

getElementsByName() [attribute name ]

[attribute ] getElementsByTagName()

getElementById()

[].forEach.call( document.getElementsByTagName("a"), function(x) { console.log(x); });

forEach()

call()

Example:is an array method (available in ECMAScript 5 ). By using, you can apply it to the non-array returned by the DOM. The DOM frequently returnsobjects that look like arrays, but are not.

Using jQuery: jQuery is very helpful for extracting information from a web page. But you want to avoid the jQuery instance that you load from clashing with a jQuery instance that the page uses. The following code shows you how to do that.

jQuery.noConflict(true)(function($) { // code using jQuery });

true

$

jQuery

This reverts everything to the way it was before loading jQuery. Theargument means that in addition to the global variablewill also be reverted to is prior value (if any). The jQuery web site has more information on jQuery.noConflict()

Transform HTML with JQuery: The following code snippet prepends the text "BLA: " to each <h3> tag in the current web page. You can run it in Firefox on a web page that has many of those tags (for example: spiegel.de).

var d = document; var s = d.createElement('script'); s.src='https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js'; s.onload = function() { jQuery.noConflict(true)(function($){ $("h3").each(function(i,e) { e.innerHTML = "BLA: "+$(e).text(); }); }); }; d.getElementsByTagName('head')[0].appendChild(s);

Producing output

alert()

prompt()

This section describes how to show the results of your bookmarklet. You always haveor(which allows you to show a text to be copied to the user), but it is usually better present your results via HTML.

Show output in the current tab:

document.body.innerHTML="<h1>Hi!</h1> Test!";

Show output in a new tab:

var d=window.open().document; d.write("<html><body><h1>Hi!</h1> Test!</body></html>"); d.close();

Minify the bookmarklet code

Variable names can be minified.

Property names cannot be minified.

$ java -jar yuicompressor-2.4.6.jar copy_url.js

javascript:(function(){var e=window.open().document;var c=(window.getSelection?""+window.getSelection():"").replace("<","<");var b={h:document.location.href,t:document.title,st:(c?"



"+c:c),sh:(c?"<br>"+c:c)};e.write(("<html><head><title>Copy link: {t}</title></head><body><a href='{h}'>{t}</a>{sh}<br><br><textarea id='text' cols='80' rows='10'>{t} {h}



<a href='{h}'>{t}</a>{st}</textarea></body></html>").replace(/{([a-z]+)}/g,function(d,a){return b[a]}));e.close()}())

(function() { var d=window.open().document; var s=(window.getSelection?""+window.getSelection():"") .replace("<","<"); var a={ h: document.location.href, t: document.title, st: (s ? "



"+s : s), // selection as text sh: (s ? "<br>"+s : s) // selection as HTML }; d.write( ("<html><head><title>Copy link: {t}</title></head><body>" +"<a href='{h}'>{t}</a>{sh}<br><br>" +"<textarea id='text' cols='80' rows='10'>" +"{t} {h}" +"



<a href='{h}'>{t}</a>" +"{st}" +"</textarea>" +"</body></html>" ).replace(/{([a-z]+)}/g, function(g0,g1){return a[g1]}) ); d.close(); }())

Mini-templating: The HTML in the output window is produced by inserting the property values of a into a text string, via the replace() method. Embedded references to the property values look like this: {t} refers to property t .

into a text string, via the method. Embedded references to the property values look like this: refers to property . Doing something with the currently selected text: window.getSelection() is only used if the browser has implemented it.

Escaping

The link: Most modern browsers don’t place any limits on the characters of a javascript: URL. If you want to make sure that it works in old browsers, you can URL-encode the “body” of a bookmarklet: > "javascript:"+encodeURIComponent('alert("hello: world/universe")') 'javascript:alert(%22hello%3A%20world%2Funiverse%22)' Try out the link inside the single quotes in a browser, it correctly brings up an alert.

URL. If you want to make sure that it works in old browsers, you can URL-encode the “body” of a bookmarklet: Try out the link inside the single quotes in a browser, it correctly brings up an alert. The link in HTML: You face a different problem if you make the bookmarklet URL the value of an attribute in HTML. With URL-encoding nothing needs to be done, but if you use unencoded JavaScript, you need to escape some characters that are illegal inside the quotes of an attribute value. <a href="alert("hello: world/universe")">link</a> The following table shows you what to escape: Escape as < < > > " " ' '

The following table shows you what to escape: Composing URLs with query parameters in a bookmarklet: use encodeURIComponent() for the parameter values. location.href='http://example.com/postLink?url=' + encodeURIComponent(location.href);

Invoking a bookmarklet via a browser keyword

Keyword name: js

Keyword URL: javascript:alert(%s)

js 7*45

javascript:alert(7*45)

Update 2011-06-11

Yahoo has implemented the YUI Compressor , a tool that minifies your bookmarklet code (makes it as small as possible, without changing what it does). YUI Compressor can be downloaded as a JAR file which makes it easy to install.Example interaction:The following code has been minified by YUI Compressor.The original looks as follows.This code is the “copy link” bookmarklet , which uses two notable techniques: Browser keywords allow you to define a command with a single argument that can be entered in the address field. That command is translated to a URL which is visited. You can combine this mechanism with a bookmarklet, to receive data from the address field. Example: Create the following browser keyword.Now you can type in the address bar:And “go” to the following URL:The blog post “ Tip: use JavaScript as a calculator in Firefox and Chrome ” has more details.There is a great thread on ycombinator with comments on this post. Read it, lots of good stuff!