How to build a Chrome extension, Part 3: Loading any web page in a popup

Chrome allows extensions that use its page action or browser action API to show popups when clicked. To add this popup, you’d add a popup.html file to your extension and the following to the manifest.json for browser actions:

{
	"name": "My Extension",
	...
	"browser_action": {
		"default_icon": "myicon.png",
		"popup": "popup.html"
	}
	...
}

Or for page actions:

{
	"name": "My Extension",
	...
	"page_action": {
		"default_icon": "myicon.png",
		"popup": "popup.html"
	}
	...
}

However, the popup page is static and cannot be changed while the extension is running. Also, only a local extension page can be put into a popup; you can’t load an external page.

So how can you fix this? Using a relatively old web technique called an iframe. Inline frame, or iframe, is an HTML element that can load any web page inside another in a type of box. So, even though you can’t load an external web page as your popup, you can load it within it.

A simple example for a Bing search extension would be:

<html>
<head>
	<style type="text/css">
	body {width:200; height:300;}
	</style>
</head>
<body>
	<iframe src="http://m.bing.com" width="100%" height="100%" frameborder="0">
	</iframe>
</body>
</html>

As you can see, I have loaded the mobile version of Bing, http://m.bing.com. Because of the small amount of screen real estate available on the popups, loading mobile versions of a page is a good idea as they are minimalistic and require less space.

I’ve also explicitly declared the size of the page (200 by 300) and the iframe (100% of the page). You can change this to what fits your extension best.

(Yeah, I know it is ironic to build a Chrome extension centered on Bing, but I couldn’t get Google’s mobile search to load correctly in an iframe.)

On Chrome, the Bing search extension would look like this:

image

You can download the completed Bing extension from the Chrome Extensions Gallery and the source code (under the GPLv2) from Mediafire.

Now, what if you want to load a different page depending on an extension option? You can easily do this by constructing the iframe element dynamically when the page loads, like this code excerpt from ChromeMilk:

$(document).ready(function() {
	var popup = localStorage.popup || 'igoogle';

	var frame = document.createElement('iframe');

	frame.setAttribute('width', '100%');
	frame.setAttribute('height', '100%');
	frame.setAttribute('frameborder', '0');
	frame.setAttribute('id', 'rtmframe');

	if (popup == 'gmail') {
		// open gmail gadget
		$('body').height(300).width(200);
		frame.setAttribute('src', 'http://www.rememberthemilk.com/services/modules/gmail/');
	}
	else if (popup == 'iphone') {
		// open iphone web app
		$('body').height(480).width(320);
		frame.setAttribute('src', 'http://i.rememberthemilk.com/');
	}
	else if (popup == 'mobile') {
		// open mobile web app
		$('body').height(300).width(200);
		frame.setAttribute('src', 'http://m.rememberthemilk.com/');
	}
	else {
		// igoogle and default
		$('body').height(400).width(400);
		frame.setAttribute('src', 'http://www.rememberthemilk.com/services/modules/googleig/');
	}

	document.body.appendChild(frame);
});

This way, the extension sets the popup size and the iframe location based on a setting saved by the user.

There are a few limitations of this method. Most importantly, you can’t manipulate the iframe once it is loaded, as this is cross-side scripting and is prevented by the browser for security reasons.

That’s about it on loading external web sites in popups. You can use this for a number of things. I’ve mentioned mobile sites, but things like iGoogle widgets also work well.

Do you have any tips on building Chrome extensions based on popups? Or are you having trouble building your extension? Leave a comment!