HTML5 context menus in Firefox (Screencast and Code)

You may not know it, but the HTML5 specifications go beyond what we put in the pages and also define how parts of the browser should become available to developers with HTML, CSS and JavaScript. One of these parts of the specs are context menus, or “right click menus”. Using HTML5 and a menu element you can add new options to these without having to write a browser add-on. In Firefox 8 (the current one) we have support for those. See the following screencast for a context menu demo.

The image example is pretty simple and was actually written by Paul Rouget as a demo in the original Firefox bug request. The main core is the HTML of it:

<section id="noninteractive" contextmenu="imagemenu">
  <img src="html5.png" alt="HTML5" id="menudemo">
    <menu type="context" id="imagemenu">
      <menuitem label="rotate" onclick="rotate()"
      <menuitem label="resize" onclick="resize()"
      <menu label="share">
        <menuitem label="twitter" onclick="alert('not yet')"></menuitem>
        <menuitem label="facebook" onclick="alert('not yet')"></menuitem>

As you can see you link the menu element to an element via its ID. The contextmenu attribute then points to this one. Each menu can have several menuitems. Each of those gets a textual label and a possible icon. You can also nest menu elements to create multiple layer menus. Here, we add inline onclick handlers to point to different JavaScript functions to call when the menu item gets activated. The resulting context menu looks like this:

image with a context menu

The functionality is simple, all the rotate() and resize() functions do is add class names to the image using querySelector and classList:

function rotate() {
function resize() {   

The real effect is in CSS transforms and transitions. As the image has an ID of menudemo here is what is needed in CSS to rotate and resize:

#menudemo { 
  -moz-transition: 0.2s; 
#menudemo.rotate { 
  -moz-transform: rotate(90deg); 
#menudemo.resize { 
  -moz-transform: scale(0.7); 
#menudemo.resize.rotate { 
  -moz-transform: scale(0.7) rotate(90deg); 

Notice that in a real product we should of course add the other browser prefixes and go prefix-less but as the functionality now only works in Firefox, this is enough for this demo.

Detecting support and visual hinting

Now, as this is extending the normal user offerings in the browser we need to make it obvious that there is a right-click menu available. In CSS3, there is a context-menu cursor available to us. When context menus are available, this should be shown:

.contextmenu #menudemo, .contextmenu .demo {
  cursor: context-menu;

We test the browser for support by checking for contextmenu on the body element and for HTMLMenuItemElement in the window (this has been added as a pull request to Modernizr, too).

if ('contextMenu' in document.body && 'HTMLMenuItemElement' in window) {
} else {

Wouldn’t HTMLMenuItemElement be enough? Yes, but a real context menu should only offer functionality when it is sensible, and that is where contextMenu comes in.

Turning menuitems on and off depending on functionality

As a slightly more complex example, let’s add a “count words” functionality to the document. For this, we generate a counter element that will become a tooltip when the words were counted:

var counter = document.createElement('span'); = 'counter';
counter.className = 'hide';
counter.addEventListener('click', function(ev){
  this.className = 'hide';

This one is hidden by default and becomes visible when the hide class is removed. To make it smooth, we use a transition:

  position: absolute;
  background: rgba(0,0,0,0.7);
  padding:.5em 1em;
  color: #fff;
  border-radius: 5px;
  -moz-transition: opacity 0.4s;
  opacity: 0;

We start with two sections with context menus:

<section id="noninteractive" contextmenu="countmenu">
  <menu type="context" id="countmenu">
      <menuitem class="wordcount" label="count words"></menuitem>
<section id="interactive" contextmenu="countmenuinteractive">
  <menu type="context" id="countmenuinteractive">
      <menuitem class="wordcount" label="count words"></menuitem>

We then loop through all the menuitems with the class wordcount and apply the functionality.

var wordcountmenus = document.querySelectorAll('.wordcount'),
    i = wordcountmenus.length;
while (i--) {
  wordcountmenus[i].addEventListener('click', function(ev){
    // add functionality 
  }, false);

We need to find out what has been selected in the page. We do this by using getSelection() and splitting its string version at whitespace. We then show the counter by removing the hide class name.

var wordcountmenus = document.querySelectorAll('.wordcount'),
    i = wordcountmenus.length;
while (i--) {
  wordcountmenus[i].addEventListener('click', function(ev){
    var text = document.getSelection(),
        count = text.toString().split(/\s/).length;
    counter.innerHTML = count + ' words';
    counter.className = '';
  }, false);

You can see this in action in the second context menu demo. Now, the issue with this (as explained in the screencast) is that it always counts the words, regardless of the user having selected some text. What we want is the menu only to be active when there is text selected.

context menu item available or not available depending on selection

So in order to make our menu only become available when it makes sense we check if there is a selection in the document. Every context menu fires an event called contextmenu when it opens. So all we need to do is to subscribe to this event.

When something is selected in the document document.getSelection().isCollapsed is true. Otherwise it is false, so all we need to do is to enable or disable the menu item accordingly:

  'contextmenu', function(ev) {
    this.querySelector('.wordcount').disabled =

The last thing to solve is the position of the mouse to position the counter element. As the menu selection event doesn’t give us the mouse position we need to add a contextmenu handler to the whole document that positions the counter invisibly behind the menu when it is opened:

  'contextmenu', function(ev) { = ev.pageX + 'px'; = ev.pageY + 'px';
    counter.className = 'hide';

Further reading and resources

View full post on Mozilla Hacks – the Web developer blog

14 thoughts on “HTML5 context menus in Firefox (Screencast and Code)

  1. Daniel Piechnick

    I can see a lot of different applications for this. Can we expect this in IE anytime soon? 🙂

    Daniel Piechnick

  2. Jonas Finnemann Jensen

    My point is that from a usability point of view, letting people remove default context menu items would make sense.

    And if some web devs, wishes to destroy the default usability by abusing this feature, that’s their loss.

    I agree that alerts with “you can’t right click here” are silly, but why not let the silly people be silly if they want to so badly? 🙂

  3. Jonas Finnemann Jensen

    This would be awesome, if I’m writting a web app there’s no reason why “View Source”, “Save Image”, etc. should take up space in the context menu. They’re not useful if a web app, why should I be able to save the image of a button?

    People can always find these options elsewhere, like in a menu or download the source manually.

    My point is that when you force web apps to have all these left-over things that are only useful for when a website is a document, you’re making the web application platform less appealing.

    Trust the web developer, if they want to obscure images, which is as you put it “silly”, they can just do it using js, css or whatever.

  4. Luke Dorny

    Just a nitpic as we discuss html5, usage of the Section element without a heading inside it. If not, it should be a div or something better.
    Otherwise a fascinating new realm of possibilities making your site feel like it is an app, or better. Awesome article.

  5. Ronny

    Hey Chris, thanks for the write-up! This is cool.
    The first thing I thought of when reading this article was “hehe let’s try to replace a default action like Back with some custom action, could be fun”.
    So I guess “only add” is a good call 😉

  6. Rodney Rehm

    Nope, haven’t opened any bugs yet. Should I do that before hand, or wait for some mozillian discussion? And thanks for updating the link 🙂

  7. Chris Heilmann

    Actually it is because we were talking to each other when I was showing him the native implementation and he went for it. He was the first to tweet back and start the discussion on Google+. Nothing about being famous at all. Great to get your resources and feedback. I will try to find out who is the best person to talk to you about it. Is there a bug open on the issue with checkboxes?

  8. Rodney Rehm

    I find it pretty interesting, that you guys link to Addy Osmani’s fork of the HTML5 contextmenu polyfill. His repo is out of sync. You’ll find the real deal at 🙂 – Native Demo here:

    I’d be interested in finding out how this happened. Is it because Addy Osmani is a namel well known on the net and I am not? Or did the guy looking for a polyfill just link to the first hit on google?

    Is there a road map regarding your context menu stuff? Currently one cannot (optically) tell aparty controls, checkboxes and radio elements within a context menu. (Amongst other difficulties I have with the native implementation). Who would I bug with my questions?

  9. passcod

    I think that’d be rather inconvenient, and might actually be a security risk. The first silly use would probably be to disable to “View Source” menu item or the “View Image”/”Save Image” items for pseudo-protection… but I think it could go much further than that, exploit-wise.

  10. fpiat

    Can we only had new options or have we methods / attributes for disabling or hiding the browser menu options?

  11. Mårten Björk

    Great news! How accessible is this? For instance, is there any way to indicate that the word count is a result of the action in the contextual menu?

Leave a Reply