Building a Firefox extension to highlight text

When I'm reading technical books on paper, I often highlight takeaways as I go, and then come back later to skim the highlighted passages and write notes.

For a while now I've wanted to be able to do this when reading long web pages, but browsers don't provide this as a feature, and I couldn't find a suitable Firefox extension, so I wrote one:

Screenshot of the highlighting

(If you're dying to find out how the text in the screenshot ends, you can find out here.)

If you press Ctrl + Shift + L when some text is selected, it will be highlighted as in the screenshot. If you press Ctrl + Shift + :, then all highlighted snippets on the page will be copied to the clipboard. Both these functions are also available through the right-click context menu.

That's it. Highlighting is not persisted between page visits.

1. Existing solutions

There are some existing Firefox extensions that provide highlighting features (eg. Textmarker), but they tend to either:

  1. have a lot of features that I don't want to manage,
  2. not have keyboard shortcuts,
  3. not offer clipboard export, and/or
  4. have very few users, in which case I prefer not to use them, because highlighting features like this require permissions to view all website data.

2. Learning how to write Firefox extensions

I hadn't done any webextensions work previously, but I suspected that it wouldn't be much effort to build these features. I needed to find out:

How to layout an extension and get it to run locally

This is covered in Mozilla's your first extension tutorial. Ultimately I just needed three files:

  1. manifest.json, which contains some metadata about the extension,
  2. content.js which runs in the context of a each web page, and
  3. background.js, which runs independently of any particular pages or windows.

These files have to be bundled into a zip folder, which can be installed directly using Firefox Developer Edition.

What permissions configuration would be required

<all_urls> was required to run on all web pages, contextMenus was required to add items to the right-click menu, and clipboardWrite was required to write to the clipboard.

How to add keyboard shortcuts

This was accomplished through the usual JS event listeners for keydown.

How to write to the clipboard

There is a navigator.clipboard API, which worked fine.

How to highlight text

This part I already knew - it's trivial to add some CSS styling.

How to add right-click context menus

This required using the background script, and sending messages between background.js and content.js.

How to get the extension signed so I could run it on Firefox

I wanted to do this without having to go through the audit process for AMO and publishing it publicly. Once I had read the docs it was simple: you sign up at https://addons.mozilla.org, upload an extension, choose the option to not publish a public version, and then wait for the automated signing process to run. After a few minutes you receive an email, and a new "approved" version will appear on the addon page in your account. You can click to install the new version in Firefox.

3. The result: a super dumb web highlighter

You can find the code on Github: https://github.com/mattduck/firefox-sdwh. It's not very good, but it (mostly) works, and I'm finding it helpful.

I haven't made it downloadable publicly. I may do that later when I've used it for a while, am confident there aren't any issues, and have put the time in to let users customise it (eg. right now the keyboard shortcuts are hard-coded).

4. Extending your tools is fun and useful

I'm pretty fluent at extending typical developer tools (the shell, Emacs etc.), but hadn't applied this to the browser before. Now that I've done it once, it will be trivial to add small features in the future.

I think this is one of the major benefits of knowing how to code - having the ability to build and customise your software tools in a way that makes sense for you personally. If you have any ideas for features that you wish were included in Firefox, I recommend finding some boilerplate from the Mozilla docs and giving it a go.

2020-Jun-27