John D. Johnson II

Written by John D. Johnson II who lives and works in Utah.

About Me


Social Links: Twitter, Github, LinkedIn

How to Quickly Create Your Own Feature Rich Bookmarklets

September 29, 2019

So, you want to allow users to run arbitrary code on a page you don't have access to or influence over. One solution is to create a browser plugin, but there is another solution that is actually quite old, but still well supported and it's called a bookmarklet. The way you generally use a bookmarklet as a user is to drag it to your bookmarks bar and click it on a given page.

So, if you've ever wondered how to make a bookmarklet it's basically a link whose href looks like this href="javascript:<your-code-here>;" where <your-code-here> is a JavaScript expression. Here's an example bookmarklet with its html that appends Hello World to the document.

<a
href="javascript:document.body.appendChild(document.createTextNode('Hello World'));"
>Say Hello</a
>

Creating a feature rich bookmarklet may seem hard due to it being a single expression that has to go inside the href's javascript: ; statement, but there are a few tricks we can use to make it much simpler.

If you wanted to make a more complex bookmarklet you would have to wrap it in an Imediately Invoked Function Expression or IIFE which basically is just a function expression that invokes/calls itself like so:

(function() {
/* Your code here */
})();

You can use this method directly by just writing a multiline function inside your a tag's href attribute surrounded by the previously pointed out javascript: ; statement. Your editor probably won't have syntax highlighting and linting features available inside that string, so development could be tedious. So, you can get around this by creating a function and programmatically turning it into a string and wrapping that with parenthesis to turn it into an IIFE and inserting that into the a's href. That could like like this:

// Bookmarklet making function:
function makeBookmarklet(bookmarkletTitle = "bookmarklet title") {
const aElement = document.createElement("a");
aElement.href = `javascript:(${main.toString()})();`;
aElement.appendChild(document.createTextNode(bookmarkletTitle));
document.body.appendChild(aElement);
const div = document.createElement("div");
const text = document.createElement("textarea");
text.appendChild(document.createTextNode(aElement.outerHTML));
div.appendChild(text);
document.body.appendChild(div);
}
makeBookmarklet();
// example function:
function main() {
document.body.appendChild(
document.createTextNode("You clicked the bookmarklet")
);
}

That's pretty awesome! Now anything we write in the function main will be code that is run by our bookmarklet. We just have to distribute the a tag code given in the textarea. This is pretty much the finished product for productively creating bookmarklets, but there is a warning ahead when using this method and also some cool bookmarklets I have made in the past as examples down below.

Try clicking the above link check your browser console to see it run. Also, hover over the link in the preview and notice that all the javascript appears on one line. This property of a bookmarklet actually adds a few complications to writing your functionality in the main function. For example if we place a single line comment in our main function it will no longer work. Another way that things could go wrong is if your code does not have semicolons. Though semicolons are avoidable most the time in JavaScript semicolons are not avoidable in the case of the single line bookmarklet. Here's an example of a comment in main that ruins the bookmarklet's execution.

WARNING: This code example is broken on purpose for explanatory purposes:
// Bookmarklet making function:
function makeBookmarklet(bookmarkletTitle = "bookmarklet title") {
const aElement = document.createElement("a");
aElement.href = `javascript:(${main.toString()})();`;
aElement.appendChild(document.createTextNode(bookmarkletTitle));
document.body.appendChild(aElement);
const div = document.createElement("div");
const text = document.createElement("textarea");
text.appendChild(document.createTextNode(aElement.outerHTML));
div.appendChild(text);
document.body.appendChild(div);
}
makeBookmarklet();
// example function:
function main() {
// this comment breaks the bookmarklet
document.body.appendChild(
document.createTextNode("You clicked the bookmarklet")
);
}

So, this code doesn't work. Hover over the link in the preview and notice how it comments the whole rest of the code. You could also check your browser console for errors when you click the link which in Chrome states "Uncaught SyntaxError: unexpected end of input". However, though you can't use single line comments you should be able to use multiline comments just fine.

So, that's basically it. Go have some fun and create something cool! Just to give you some ideas here are some bookmarklets I have made in the past.

codepen

codepen

codepen

codepen

codepen