The amazing adventures of Doug Hughes

Occasionally I have to work on web applications that are horribly slow. Some complex applications can take several minutes to completely reload. Im sure Im not alone in this experience. And so, when working on these sites, what do you do while waiting for stuff to load? If you’re like me, you go to another tab and work on something else while you wait for that tab to load (or you troll around Twitter, etc).

This isnt really a problem except that more often than not I fail to notice when the other tab has finished loaded and end up wasting time. Because of this, Ive long wished that there were a tab extension that would could play a sound when a tab finishes loading. However, look as I may, I never found anything that did what I wanted.

In the past Ive considered writing a simple extension for this. The thing is, until recently Ive been a fairly diehard Firefox user. Having written a now-defunct Firefox extension, I know what a flaming pain in the ass it is to write Firefox extensions. There was no way I was going to write this extension for Firefox.

However, I recently decided to take Google Chrome for a real test drive and Ive been using it exclusively for a few weeks. During this period I also began working on a website that takes a very long time to reload. So long, in fact, that I became frustrated enough to go and research whats involved in making extensions for Chrome. And, as it turns out, theres not a whole lot involved!

In Firefox, when you write an extension you can change or override just about any feature of the browser. For example, if you dont like how bookmarks system works, you can pretty much replace it with something you do like. The thing is, with all that power and flexibility comes a boatload of complexity. I really dont even have the patience to write about the hoops I had to jump through to get started. Let it suffice to say that I had to run the browser in a different test user account and, if I recall correctly, reload the browser each time I made a chance to my extension. Then theres the fact that Firefox extensions are written using XUL (XML User Interface Language). And there was more fun too. In summary: Its a pain and no fun at all.

Chrome, by contrast, is much more limiting in what you can do. However, its API is a dream to work with. In Chrome most extensions are either browser actions, which are browser-wide, or page actions, which only affect the current page. Both of these are quite easy to write, but Ill focus on browser actions since thats what I wrote.

In addition to the two basic extension points, Chrome also provides a nice API for interacting with browser features such as bookmarks and tabs. Like everything else in Chrome, these APIs are very simple and easy to use.

At a minimum, Chrome extensions are made up of HTML files and a manifest file written in JSON. The manifest defines basic information like the name, version, description, icons, etc.

It also defines a background page. A background page is a page that is loaded by the extension and runs constantly behind the scenes. This is useful for storing state information and providing the core features of the plugin.

The manifest also allows you to define browser actions. Browser actions define an image or button that appears to the right of the address bar and provides an entry point into your extension. When you click on that icon a popup you create appears.

Here was the manifest for my plugin:

  "name": "Tab Bing!",
  "version": "1.1",
  "description": "This extension produces a 'bing' when a tab finishes loading.",
  "icons": { "128": "bell_128.png" },
  "background_page": "background.html",
  "browser_action": {
    "default_title": "",
    "default_icon": "bell_19.png",
    "default_popup": "popup.html"
  "permissions": [

The manifest file above defines the name, etc, of my extension. It also says that the background page, background.html, will be loaded and run behind the scenes at all times. Additionally, there will be a button to the right of the nav menu. Clicking this button will show the popup, popup.html.

At this point all I need to do is create the files referenced and load the extension into Chrome. Just for an example, here is the directory structure of my extension:

Files in Tab Bing!

You can ignore the mp3 files and play.png file as theyre my extension’s assets. Really, what I have is three very simple: manifest.json, background.html, and popup.html.

If I wanted to load my extension into my browser how I can do so by putting the extension tab into developer mode. I do this by opening the extensions tab and clicking on the Developer mode link.

Developer Mode

After that I can click on Load Unpacked Extension and simply choose the directory my extension is in. At this point I can see my button appear next to the tool bar. Clicking the button shows a popup window containing the contents of my popup.html file. It really doesnt get much simpler than this!

Now that I have the basics of my Chrome extension in place I can start writing my extensions features.

The way my extension works is to allow the user to indicate if they want the current tab to bing when done loading. To support this Ive created a simple popup that collects a few options from the user. These options are stored by the background.html file that is persistent for the duration of the browsers lifespan.

So, heres my popup.html:

	width: 300px;
	font-family: verdana;

	var background = chrome.extension.getBackgroundPage();
	var tab = null;
	var tabSettings = null;
	var previewedSound = null;
	// get the current tab
	chrome.tabs.getSelected(null, function(_tab){
		tab = _tab;


		tabSettings = background.bingTabs[];

		// check the bing box
		document.getElementById("bing").checked =;

		// select the sound
		var sound = document.getElementById("sound");
		for(var i = 0 ; i < sound.options.length; i++){
			var option = sound.options[i];
			if(option.value == tabSettings.sound){
				sound.selectedIndex = i;

		// check the repeat box
		document.getElementById("repeat").checked = tabSettings.repeat;

	function toggleBing(bing){
		background.bingTabs[].bing = bing;

	function selectSound(sound){
		background.bingTabs[].sound = sound;

	function toggleRepeat(repeat){
		background.bingTabs[].repeat = repeat;

	function insureElementExists(){
		if(background.bingTabs[] == undefined){
			background.bingTabs[] = {
				bing: false,
				sound: "Bing",
				repeat: false,
				playing: null

	function preview(sound){
		if(previewedSound != null){
		previewedSound =, false);

	 Make this tab bing when loaded.
	Choose a sound:

		Door Buzzer
		Smoke Alarm

	<img src="play.png" />
	 Repeat until the tab is selected.

The first thing you may note is that this looks pretty much like any HTML file. Thats because it is! Take a look at the body and note that Im using HTML form elements to define my popup. Heck, I even use CSS to format the popup!

Heres what it looks like in the browser:

The Extension's Popup

Looking at the JavaScript in the popup youll see that I have this line of code first:

var background = chrome.extension.getBackgroundPage();

This returns a reference to the background.html page. Once I have this reference I can call functions on it. Before I show that though, let me show you the code for the background.html:

		function(tabId, changeInfo, tab) {
			if(changeInfo.status == "complete"){
				if(bingTabs[tabId] != undefined &amp;&amp; bingTabs[tabId].bing){
					if(currentTab != tabId &amp;&amp; bingTabs[tabId].repeat){
						bingTabs[tabId].playing = play(bingTabs[tabId].sound, true);
					} else {
						bingTabs[tabId].playing = play(bingTabs[tabId].sound, false);

	chrome.tabs.getSelected(null, function(tab){
		currentTab =;

		function(tabId, selectInfo){
			currentTab = tabId;


	var bingTabs = {};

	function bing(id){
		sound = bingTabs[id].sound;
		play(sound, false);

	function play(sound, repeat){
		var audio = new Audio(sound + ".mp3");

			audio.loop = true;

		return audio;

	function stop(sound){

Not a very long script is it? Its entirely JavaScript too!

What this does, is make use of the Chrome extension API to listen for tab updated events. When they occur it looks to see if that specific tab is set to bing. If so, it bings by using the HTML 5 audio API to play an MP3 file.

Going back to the popup.html, when you check the checkbox to make the tab bing, the checkboxs onChange event calls the toggleBing() function. This toggleBing() function simply calls the background page and tells it to make that tab bing when done loading.

What I really think is cool about Chrome extensions are how quickly I got up to speed.It literally only took about half an hour and I was off to the races. The Chrome extensions documentation is terrific to! And once I had a working version I was able to quickly and easily make changes to add additional features. You do have to click reload in the extensions tab, but that beats the pants off reloading the entire browser with each change.

Additionally, with Firefox, it was really very difficult to publish the extension to For Chrome it was as simple as uploading my extensions folder to Googles Chrome extensions website.

The biggest gripe I have, though, is that Chrome’s simplicity is also a little limiting. I cant completely change any feature within the browser. But, in all honesty, I think its a good tradeoff for a much nicer user experience.

If you’re interested you can download my Tab Bing! Chrome extension here.

I figure that next Ill make my Tab Bing! extension make the tabs icon blink when a tab is loaded! What extensions would you create if you had the time and know-how?

Comments on: "Google Chrome Extensions are Crazy Easy" (5)

  1. Excellent post, very well written and informative. The code snippets are excellent too. This might inspire me to give it a go myself.


  2. good job


  3. Awesome post. Awesome post.

    Thank you.


  4. Great post!!!!!


  5. […] for trying to help. I think you can use a code like this but i can't figure out how to do it. Google Chrome Extensions are Crazy Easy – Alagad Ally […]


Comments are closed.

Tag Cloud

%d bloggers like this: