Creating your first Opera widget
By Opera Software · 22 Jan, 2008
- Table of contents/first article—Opera Widgets SDK
- Next article—Packing and deploying your Opera Widget
Creating an Opera widget is quick and painless, with just a few pointers in the right direction. This article details what a widget is and what you need to create one, and also takes you through creating, running and packaging a widget step by step. The basic techniques discussed here also apply to widgets intended to run on mobiles, set-top-boxes or within the Opera browser on the Nintendo Wii Internet Channel.
Before you get started
OK, we know you can’t wait to get started, but bear with us for just a moment while we run through a few essential basics.
What are widgets?
Widgets are small web applications running on your desktop. They are implemented using client-side web technologies, and creating one is very much like creating a web page, except that it is run in a slightly different context.
Opera browsers can install and open these widgets, showing them directly on the user’s desktop (or equivalent in other devices.) Widgets are chromeless applications, display without regular user interface elements such as a back button or address field. When run on a desktop computer, widget look something like the clock widget shown in Figure 1.
Figure 1: An analog clock, displayed directly on the user's desktop
Packaging widgets
Opera Widgets are packaged as regular zip files, renamed to use the extension .wgt. All the files related to your widget should be stored inside the widget file. A typical widget contains the following elements:
- A widget configuration file. This is an XML file in the root of the widget structure that holds information about your widget including its size, name, author, and security information.
- An index document. Like on a web page, this document contains the basic skeleton/content of the widget. Widgets content can be created using any markup that Opera handles natively, for example HTML, SVG, or XML files. This file also lives in the root of the widget structure.
- Images. These are contained in a single images folder.
- JavaScript files. These are contained in a single script folder.
- Stylesheets. These are contained in a single style folder.
When a user running the Opera desktop browser clicks on a link to a .wgt file, Opera will download the widget, start it, and ask the user if the widget should be kept on his/her computer. Note that behavior on different platforms supporting widgets may differ slightly. Note also that we have submitted a widget spec to the W3C for consideration, in an effort to standardize things.
The next time the user wants to run the widget, it can be started from the Widgets menu.
What do you need to create and deploy an Opera Widget?
In order to be able to create an Opera Widget, you will need the same as you need for regular Web development:
- A basic understanding of web technologies.
- A text editor or web IDE that allows creation of JavaScript, HTML, and CSS files.
- A tool for creating .zip archives.
- Somewhere to publish the widget. The Opera Widgets web site offers the perfect place to host your widgets, and is visited by tens of thousands of people every day looking for widgets to run.
How are widgets related to web pages?
We keep saying widgets are very similar to regular Web pages, but there are a few differences:
- The widget lives outside the Web browser, directly on the user’s desktop without any of the regular user interface elements, such as title bars.
- The security restrictions of a widget are different from regular web pages - you can create a widget that will simultaneously interface with different Web services living on different Web servers.
- Widgets have a
widgetobject available via JavaScript that allows you to access widget-specific functionality. - Widgets have access to a permanent storage facility for its settings and downloaded data. This mechanism is similar to cookies, but the storage capacity is larger than for cookies, and does not automatically expire after a given time.
- Widgets typically have several views available in the same document. Typically there will be one or more views used to access the widget's normal functionality, and a separate view wherein you provide the user with configuration options. Switching between these views is done by performing transitions on the views using regular JavaScript/CSS methods.
- By default, widgets are draggable, so you can move them around on the screen simply by clicking and dragging. If this behavior is not desired for a widget (or parts of it,) you need to specify control regions where the widget does not respond to dragging.
- By default, the widget background color is transparent. The transparent area of a widget does not respond to mouse events but instead passes them through to any underlying application.
The widget workshop: hello world!
OK, with the background out of the way, let’s start coding! Our first widget will be as simple as possible - a “Hello World!” widget. Earlier on we talked about widgets containing CSS, Imaga and JavaScript files. Many do, but at the very least, a widget requires two files:
- The main document.
- The widget configuration file.
We will start this tutorial by creating a minimal widget, and then expand the widget into a complete widget with style, and a configuration view.
Creating the main document
First, create an HTML document inside a new directory and call it index.html. This document will be what your users will see when they first load the widget. Add the following code to it, and save the document.
<!DOCTYPE html>
<html>
<head>
<title>Hello World!</title>
</head>
<body>
<p>Hello World!</p>
</body>
</html>
Creating the widget configuration file
Next, we'll show you how to create the widget configuration file, which is needed in order to run your widget. It is always named config.xml, and holds information on certain properties of the widget. The properties required inside this file are as follows:
- The widget’s name.
- The widget’s dimensions. This is the maximum viewable area for a widget.
- Author information. Feel free to brag.
- A unique ID for the widget. This ID is made up of three parts: A hostname, a path and a revision date on the
YYYY-MMformat (you can also useYYYY-MM-DDDDif you plan on revising the widget more than once a month). - Security information that provides the widget user with information about which domains the widget will be contacting. Even if this security information is optional, any widget that contacts a third-party service is highly encouraged to include this, since this will establish a trust relationship between you, the widget author, and the widget user. For more information, view the config.xml specification here.
Create a new file in the same directory as your index.html file called config.xml. Add the following code to it, and save it.
<?xml version='1.0' encoding='UTF-8'?>
<widget>
<widgetname>Hello World!</widgetname>
<description>Demo widget from the Hello World tutorial.</description>
<width>440</width>
<height>200</height>
<author>
<name>John Doe</name>
<email>john.doe@example.com</email>
<link>http://acme-widget.example.com</link>
<organization>Acme Examples, Inc.</organization>
</author>
<id>
<host>example.com</host>
<name>HelloWorld</name>
<revised>2008-01</revised>
</id>
</widget>
Running your widget for the first time
Let's test what we have so far - run your widget by opening the config.xml file in the browser (by dragging it into the browser window, using the OperA File → Open menu, or whatever other method you'd prefer.) When you run the widget defined above, you should see something like that shown in Figure 2.

Figure 2: Running an unstyled Opera widget.
Adding style
In its current form, the widget’s default background color is transparent, and uses regular browser defaults for styling. Ugh! Let’s spice it up with a little CSS and additional markup.
First, you need to add a stylesheet reference to the HTML document, and add some hooks for styling. Replace what you currently have inside index.html with the following, and save the changes.
<!DOCTYPE html>
<html>
<head>
<title>Hello World!</title>
<link rel="stylesheet" type="text/css" href="style/helloworld.css">
</head>
<body>
<div id="container">
<div id="header">
</div>
<div id="content">
<h1>Hello World!</h1>
</div>
<div id="footer">Powered by Opera</div>
</div>
</body>
</html>
Next it's time to create a stylesheet to style your widget. Create a new folder called style, and create a new file inside it called helloworld.css. Add the following code inside this file and save it.
/** Basic styles **/
body {
font-family: Verdana, Helvetica, sans-serif;
font-size: 16px;
}
h1 {
margin: 0;
font-size: 1.1em;
padding: 7px 0 0 10px;
font-weight: normal;
}
h2{
font-weight: normal;
font-size: 1.1em;
margin: 0px;
}
/** Structure **/
#container {
width: 429px;
}
#header {
background-image: url(../images/back_top.png);
padding: 4px 10px 0px 10px;
height: 35px;
}
#content {
background-image: url(../images/back_center.png);
color: #333;
}
.view{
padding: 10px 10px 10px 20px;
height: 60px;
max-height: 60px;
max-width: 393px;
overflow: auto;
-apple-dashboard-region:dashboard--region(control rectangle 0px 0px 0px 0px);
}
#footer {
background-image: url(../images/back_bottom.png);
height: 23px;
padding: 2px 0 0 20px;
font-size: 0.6em;
text-decoration: underline;
color: #dd2222;
}
You'll notice that there are several background images referenced inside this stylesheet, so now we need to add these to our widget folder. The images you need can be found in the code examples zip - download the code examples here, unzip the archive, then grab the images folder contained within it, and put it in the same directory as the index.html file.
The styling is now all in place, so try running your widget again, in the same manner as before - it should now look like Figure 3. After this styling is applied, the widget no longer looks bland and unstyled. It now has a background that makes it stand out from the rest of the desktop. The control regions make the center of the widget and any scrollbars clickable without causing the widget to be dragged.
Figure 3: The widget is now styled - much better!
A note on widget style
We’re not the fashion police, but we have nevertheless defined some simple Opera Widgets style guidelines, which we encourage you to examine. The benefit of everyone sticking to the same style for their widgets is that they become more recognizable to the end user and easier to use.
Adding interactivity
You will now have a fully working widget, but there is much farther you can go with it - it does not yet offer any interactivity, and there is no way to configure the widget. Next we will take you through adding a configuration button, which “flips” the widget over, and a close button.
Open index.html again, replace the contents with the following code, and save it.
<!DOCTYPE html>
<html>
<head>
<title>Hello World!</title>
<link rel="stylesheet" type="text/css" href="style/helloworld.css">
<script type="text/javascript" src="script/helloworld.js"></script>
</head>
<body>
<div id="container">
<div id="header">
<div id="controlbuttons">
<button id="flipbutton" class="controlbutton" type="button"></button>
<button id="closebutton" class="controlbutton" type="button"></button>
</div>
<h1>Hello World!</h1>
</div>
<div id="content">
<div id="front" class="view">
<h2 id="hellotext">Welcome to the world of Opera Widgets!</h2>
</div>
<div id="config" class="view">
<h2>Hello World! Configuration</h2>
<p>
<label for="frontlabel">Text to display</label>
<input id="frontlabel" type="text" size="25">
<button id="updatebutton" type="button">Update</button>
</p>
</div>
</div>
<div id="footer">Powered by Opera</div>
</div>
</body>
</html>
The major additions here are:
- A reference to the script that controls the view flipping, from the main view to the configuration view.
- A button for flipping between the front and back of the widget, and a close button.
- A configuration view.
Now you need to update the stylesheet, and add the JavaScript.
Styling the configuration and buttons
Add the following style rules to the helloworld.css file below the existing rules, and save the file. These rules hide the configuration view by default and control the look of the buttons.
/* Hide the configuration view by default */
#config {
display: none;
}
/** Button styles **/
#controlbuttons {
float: right;
}
.controlbutton {
opacity: 0.0;
overflow: hidden;
height: 30px;
width: 30px;
background-position: left top;
border: 0;
}
#flipbutton {
background: transparent url(../images/btn_config.png) scroll no-repeat 0 0;
}
#closebutton {
background: transparent url(../images/btn_close.png) scroll no-repeat 0 0;
}
/** Button effects **/
#container:hover .controlbutton {
opacity: 0.3;
}
#container .controlbutton:hover {
opacity: 1.0;
}
#container .controlbutton:active {
opacity: 1.0;
background-position: left bottom;
}
We’re still not the fashion police, but it is highly recommended that widgets using control buttons use them as illustrated in this tutorial:
- Widgets should always supply a close button, unless the widget is being shown on a handheld device.
- The control buttons should be invisible when the mouse is not over the widget
- They should become visible with an opacity of 0.3 when the mouse moves over the widget
- When the mouse moves over a control button, it's opacity should increase to 1.0
- When a control button is clicked, the button should change to the click state
- The control buttons should be in the upper right hand corner of the widget
Now it's time to test the widget again, to check out the new functionality. Run your widget again as before. When you hover the mouse pointer over the widget, it should look like Figure 4.
Figure 4: The initial state of the widget when moused over.
Now try mousing over a control button, and you'll see something like Figure 5.
Figure 5: The control button hover state.
Adding behavior to the buttons
The next step is to add behavior to the flip button, so that the widget shows it's other side when the flip button is clicked or activated. This behavior is controlled by some simple JavaScript, and all you need to do is put it in the right place. Look to the resource zip file you unpacked earlier to find a script folder containing a helloworld.js file. Copy this folder into the same directory as your index.html file.
The contents of the file is as follows:
// define a namespace to hold our widget specific functions,
// avoid polluting the global namespace
var helloWorld = helloWorld || {};
// function for flipping between different sides of the widget
helloWorld.flip = function ( e )
{
var display = document.getElementById('front').style.display;
if ( display == 'block' || display == '' )
{
document.getElementById('front').style.display = "none";
document.getElementById('config').style.display = "block";
}
else
{
document.getElementById('config').style.display = "none";
document.getElementById('front').style.display = "block";
}
}
// initialize the widget
window.addEventListener( 'load' , function(ev)
{
// add behavior to the flip button
document.getElementById('flipbutton').addEventListener('click',function(ev){
helloWorld.flip();
}, false);
// add behavior to the close button
document.getElementById('closebutton').addEventListener('click',function(ev){
window.close();
}, false);
// make WOC button open a browser window
document.getElementById('wocbutton').addEventListener('click', function(ev){
widget.openURL('http://widgets.opera.com');
}, false);
// add a change handler so that the widget shows whatever we input into the
// widget front, flip back to the front when done
document.getElementById('updatebutton').addEventListener('click',function(ev){
document.getElementById('hellotext').textContent =
document.getElementById('frontlabel').value;
helloWorld.flip();
},false);
// set the contents of the text field to the initial value
document.getElementById('frontlabel').setAttribute( 'value',
document.getElementById('hellotext').textContent );
},false);
In this code, we’ve encapsulated the functions specific to the widget in their own object, or namespace. This way the functions are not overriden if they have already been defined. We recommend you stay away from the global namespace as much as possible. The second half of the code is a function that runs when the widget is loaded and sets up the behavior of the buttons and the text field.
Now try running our widget, hovering it with your mouse, and clicking the cogwheel button. The the widget is flipped so that the reverse side of the widget is visable. This reverse side shows a text input field, where you can alter the text on the main view of the widget, as shown in Figure 6
Figure 6: The widget configuration view.
Distributing your widget
At this point in the article, your widget should be complete. Th final step you'll want to take is package it up, and make it available for others to download and use. There are instructions available on how to deploy your own widgets here - Check these instrictions out to find out how to do this.
Summary
Congratulations! - you have now built your first Opera Widget. Now you can move on to personalize this widget, or create some new ones of your very own.
You can download the Hello World! widget here. Click the Launch button on the download page to run the widget. If you want to save the widget zip-file on your hard drive, right click on the Launch button and select Save Link As….