Writing your first Greasemonkey script – adding menus to Facebook’s top menu
This post will show you how to write a basic Greasemonkey script that will add two more menu items to Facebook's friends top menu as shown below.

These 2 menu items are :
- "Recently Updated" - show all your friends with recent updates
- "Status Updates" - show the latest status updates of your friends
About Greasemonkey
Greasemonkey is a Firefox extension that allows you to write scripts that alter the web pages you visit. You can
- use it to make a web site more readable or more usable
- fix rendering bugs that the site owner can't be bothered to fix themselves.
- alter pages so they work better with assistive technologies that speak a web page out loud or convert it to Braille
- even automatically retrieve data from other sites to make two sites more interconnected.
Greasemonkey by itself does none of these things. In fact, after you install it, you won't notice any change at all... until you start installing what are called “user scripts”. A user script is just a chunk of javascript code, with some additional information that tells Greasemonkey where and when it should be run. Each user script can target a specific page, a specific site, or a group of sites.
Install Greasemonkey addon for Firefox
Go to Greasemonkey addon page, click on the "Add to Firefox" button and follow the instructions. After restarting Firefox, you will notice a monkey's head sitting at the bottom right its status bar.
If you right click on the monkey's head and choose "Manage User Scripts" from the resulting menu, you will notice there isn't any script which is quite normal since we have not installed any ;-).
Creating your first Greasemonkey script.
For a Greasemonkey to be recognized, it must end with .user.js, so let us create an empty file and save it as myfirstscript.user.js
Fire up your favourite text editor and open your newly created file.
Greasemonkey script metadata
All user scripts has a meta data section which tells Greasemonkey about the script itself, where it came from, and when to run it. For example, our script :
// ==UserScript== // @name My First GM script // @namespace http://htmlblog.net // @description basic Greasemonkey script // @include http://www.facebook.com/ // ==/UserScript==
You can find more information about the metadata here.
Remember we want our script available only for Facebook pages, that is why we use @include http://www.facebook.com
Show me some code.
Alright, to add our own menus, we need to get the parent element holding the drop down menu. After inspecting Facebook's source code, we can rapidly come to the conclusion that the parent element's id is "fb_menu_friends_dropdown". So the current Facebook code looks like that :
<div class="fb_menu_dropdown hidden_elem" id="fb_menu_friends_dropdown"> <div class="fb_menu_item"><a href="http://www.facebook.com/friends/?added&ref=tn">Recently Added</a></div> <div class="fb_menu_item"><a href="http://www.facebook.com/friends/?everyone&ref=tn">All Friends</a></div> <div class="fb_menu_separator"></div> <div class="fb_menu_item"><a href="http://www.facebook.com/invite.php?ref=tn">Invite Friends</a></div> <div class="fb_menu_item"><a href="http://www.facebook.com/find-friends/?ref=friends">Find Friends</a></div> </div>
and our goal is to insert the two menu items before the "Recently Added" item.
For us to do that, we need to get the first child of the parent element and then insert our elements before it and to help us, i.e walking through the DOM selecting parent and childs, I use a little piece of code found on Github, which eliminates whitespace issues between elements among other features. So our myfirstscript.user.js can be updated to :
// ==UserScript== // @name My First GM script // @namespace http://htmlblog.net // @description basic <a href="https://addons.mozilla.org/firefox/addon/748" target="_blank">Greasemonkey</a> script // @include http://www.facebook.com/ // ==/UserScript== DOM = function () { function get(id) { if (id && typeof id === 'string') { id = document.getElementById(id); } return id || null; } function walk(element, tag, walk, start, all) { var el = get(element)[start || walk], elements = all ? [] : null; while (el) { if (el.nodeType === 1 && (!tag || el.tagName.toLowerCase() === tag)) { if (!all) { return el; } elements.push(el); } el = el[walk]; } return elements; } return { // Get the element by its id get: get, walk: walk, // Returns the previousSibling of the Element (excluding text nodes). getPrevious: function (el, tag) { return walk(el, tag, 'previousSibling'); }, // Like getPrevious, but returns a collection of all the matched previousSiblings. getAllPrevious: function (el, tag) { return walk(el, tag, 'previousSibling', null, true); }, // As getPrevious, but tries to find the nextSibling (excluding text nodes). getNext: function (el, tag) { return walk(el, tag, 'nextSibling'); }, // Like getNext, but returns a collection of all the matched nextSiblings. getAllNext: function (el, tag) { return walk(el, tag, 'nextSibling', null, true); }, // Works as getPrevious, but tries to find the firstChild (excluding text nodes). getFirst: function (el, tag) { return walk(el, tag, 'nextSibling', 'firstChild'); }, // Works as getPrevious, but tries to find the lastChild. getLast: function (el, tag) { return walk(el, tag, 'previousSibling', 'lastChild'); }, // Works as getPrevious, but tries to find the parentNode. getParent: function (el, tag) { return walk(el, tag, 'parentNode'); }, // Like getParent, but returns a collection of all the matched parentNodes up the tree. getParents: function (el, tag) { return walk(el, tag, 'parentNode', null, true); }, // Returns all the Element's children (excluding text nodes). getChildren: function (el, tag) { return walk(el, tag, 'nextSibling', 'firstChild', true); }, // Removes the Element from the DOM. dispose: function (el) { el = get(el); return (el.parentNode) ? el.parentNode.removeChild(el) : el; } }; }();
To get the parent element and its first child, we then append the following code :
// get drop down menu var parentNode = DOM.get('fb_menu_friends_dropdown'); // get its first child var firstNode = DOM.getFirst('fb_menu_friends_dropdown');
Creating our nodes
Now we must create our two nodes which will be inserted afterward. This is done easily with the following code which is self explanatory :
/** For "Recently Updated" */ // create our div with class fb_menu_item var recentDiv = document.createElement('div'); recentDiv.setAttribute('class', 'fb_menu_item'); // create our link var recentLink = document.createElement('a'); recentLink.href = 'http://www.facebook.com/friends/?recent&ref=tn'; // add text to our link var recentDivContent = document.createTextNode('Recently Updated'); recentLink.appendChild(recentDivContent); // add link to our div recentDiv.appendChild(recentLink); /** For "Status Updates" */ // create our div with class fb_menu_item var statusDiv = document.createElement('div'); statusDiv.setAttribute('class', 'fb_menu_item'); // create our link var statusLink = document.createElement('a'); statusLink.href = 'http://www.facebook.com/friends/?status&ref=tn'; // add text to our link var statusDivContent = document.createTextNode('Status Updates'); statusLink.appendChild(statusDivContent); // add link to our div statusDiv.appendChild(statusLink);
We can also add a separator, for having a cleaner look :
/** Creates a separator, just to look good */ var separatorDiv = document.createElement('div'); separatorDiv.setAttribute('class', 'fb_menu_separator');
Finally we insert these 3 nodes before the first child element we got earlier on :
// add all divs before first child of menu parentNode.insertBefore(statusDiv, firstNode); parentNode.insertBefore(recentDiv, firstNode); parentNode.insertBefore(separatorDiv, firstNode);
Just to be on the safe side of things, we surround the whole block of code with a try and catch statement.
Putting it all together
So finally our code is like this :
// ==UserScript== // @name My First GM script // @namespace http://htmlblog.net // @description basic <a href="https://addons.mozilla.org/firefox/addon/748" target="_blank">Greasemonkey</a> script // @include http://www.facebook.com/ // ==/UserScript== DOM = function () { function get(id) { if (id && typeof id === 'string') { id = document.getElementById(id); } return id || null; } function walk(element, tag, walk, start, all) { var el = get(element)[start || walk], elements = all ? [] : null; while (el) { if (el.nodeType === 1 && (!tag || el.tagName.toLowerCase() === tag)) { if (!all) { return el; } elements.push(el); } el = el[walk]; } return elements; } return { // Get the element by its id get: get, walk: walk, // Returns the previousSibling of the Element (excluding text nodes). getPrevious: function (el, tag) { return walk(el, tag, 'previousSibling'); }, // Like getPrevious, but returns a collection of all the matched previousSiblings. getAllPrevious: function (el, tag) { return walk(el, tag, 'previousSibling', null, true); }, // As getPrevious, but tries to find the nextSibling (excluding text nodes). getNext: function (el, tag) { return walk(el, tag, 'nextSibling'); }, // Like getNext, but returns a collection of all the matched nextSiblings. getAllNext: function (el, tag) { return walk(el, tag, 'nextSibling', null, true); }, // Works as getPrevious, but tries to find the firstChild (excluding text nodes). getFirst: function (el, tag) { return walk(el, tag, 'nextSibling', 'firstChild'); }, // Works as getPrevious, but tries to find the lastChild. getLast: function (el, tag) { return walk(el, tag, 'previousSibling', 'lastChild'); }, // Works as getPrevious, but tries to find the parentNode. getParent: function (el, tag) { return walk(el, tag, 'parentNode'); }, // Like getParent, but returns a collection of all the matched parentNodes up the tree. getParents: function (el, tag) { return walk(el, tag, 'parentNode', null, true); }, // Returns all the Element's children (excluding text nodes). getChildren: function (el, tag) { return walk(el, tag, 'nextSibling', 'firstChild', true); }, // Removes the Element from the DOM. dispose: function (el) { el = get(el); return (el.parentNode) ? el.parentNode.removeChild(el) : el; } }; }(); try{ // get drop down menu var parentNode = DOM.get('fb_menu_friends_dropdown'); // get its first child var firstNode = DOM.getFirst('fb_menu_friends_dropdown'); /** For "Recently Updated" */ // create our div with class fb_menu_item var recentDiv = document.createElement('div'); recentDiv.setAttribute('class', 'fb_menu_item'); // create our link var recentLink = document.createElement('a'); recentLink.href = 'http://www.facebook.com/friends/?recent&ref=tn'; // add text to our link var recentDivContent = document.createTextNode('Recently Updated'); recentLink.appendChild(recentDivContent); // add link to our div recentDiv.appendChild(recentLink); /** For "Status Updates" */ // create our div with class fb_menu_item var statusDiv = document.createElement('div'); statusDiv.setAttribute('class', 'fb_menu_item'); // create our link var statusLink = document.createElement('a'); statusLink.href = 'http://www.facebook.com/friends/?status&ref=tn'; // add text to our link var statusDivContent = document.createTextNode('Status Updates'); statusLink.appendChild(statusDivContent); // add link to our div statusDiv.appendChild(statusLink); /** Creates a separator, just to look good */ var separatorDiv = document.createElement('div'); separatorDiv.setAttribute('class', 'fb_menu_separator'); // add both divs before first child of menu parentNode.insertBefore(statusDiv, firstNode); parentNode.insertBefore(recentDiv, firstNode); parentNode.insertBefore(separatorDiv, firstNode); } catch(e){};
Installing and testing our script
Fire up Firefox and select "File" -> "Open File..." in the menu bar and then browse for your script, i.e myfirstscript.user.js in our case. You will be prompted to install the script by Greasemonkey. After installation is complete, head to Facebook, login and hover over the "Friends" menu, you will see your newly created menus.
Download script
Install script
8 Comments to “Writing your first Greasemonkey script – adding menus to Facebook’s top menu”
Leave a Reply

Great article! Thanks for taking the time to explain.
I’ve been thinking about similar topics lately, and it’s good to see that I’m not alone. What do you think about Putting a YUI Face on a Java Web Application?
Alright. It adds the menus but when you click on them it just goes to the all friends list. Any way around the new face book updates
@Nathaniel unfortunately 2 days after I wrote this post, FB changed the friends list ;-( Will try to find out the link
I am trying to add an option to the “Preferences” dropdown menu in Meebo (which only shows up once you sign in). I have been trying to modify this code to work with that but I can not seem to figure out how to do so. Any ideas?
Change these lines from
recentLink.href = ‘http://www.facebook.com/friends/?recent&ref=tn’;
to
requestsLink.href = ‘http://www.facebook.com/reqs.php’;
and
statusLink.href = ‘http://www.facebook.com/friends/?status&ref=tn’;
to
statusLink.href = ‘http://www.facebook.com/home.php?filter=app_**********’;
Go to your FB home page, click on Status Updates on your left and use the number at the end in your address bar.
That worked for me, basically find the current link and adjust your old one. Face Book like to mix things up.
Your profile has been added to Island Website :-) You can access your’s here
Why would somebody’s *first* greasemonkey srcript be so “complicated” ?
Some kind of “Hello World” would be far more appropriate.
Well you have to love firefox. It seems like to much trouble for me tho..