Bring the 'jump to search' keyboard shortcut to any site with userscripts
Tags: javascript, productivity, browser, tutorial
Published: 2023-07-11 16:24:09

Some sites allow you to jump to their search bar using the `/` key (e.g., Google, GitHub, and many more). However, for sites without such a shortcut (e.g., Gmail, Bing), it can feel quite tedious to have to scroll, find, and click the search bar each time.

## The power of userscripts

This is where [userscripts](https://en.wikipedia.org/wiki/Userscript) come in: some JavaScript code that you can configure to run on any site – and they can be quite powerful! For example, [I created and maintain a userscript](https://github.com/soscripted/sox) that adds a bunch of additional optional features to the Stack Exchange network of sites (e.g., Stack Overflow). These can range from simple manipulations like tweaking the colour of an element, to full-fledged features like adding a 'find and replace' function to the post editor.

Userscripts are similar to browser extensions, but they can be much easier and quicker to customise to your liking – creating a userscript can take less than a minute, whereas setting up a full browser extension can take considerably more time, especially if you've never made one before. Userscripts are also inherently open-source, so it is easier to verify the code before you install them!

Userscripts also have [some special APIs](https://www.tampermonkey.net/documentation.php) that let you fetch resources, interact with tabs, save data, and more.

## The userscript metadata (header) block

Every userscript must start with a 'header' called the _[metadata block](https://wiki.greasespot.net/Metadata_Block)_. This is just a set of JavaScript comments, each starting with a special key-value pair. For example, `// @name My Userscript` defines the `@name` key.

The header section must start and end with the special comments `// UserScript` and `// /UserScript` respectively.

There are [many keys](https://www.tampermonkey.net/documentation.php) that can be used in the metadata block. One of the most important ones is `@match` (and also `@include` – see [What is the difference between @include and @match in userscripts?](https://stackoverflow.com/q/31817758)). This lets you specify which page(s) to run a script on.

## Interacting with the Document Object Model (DOM)

One of the main things you usually do with a userscript is interact with the [Document Object Model (DOM)](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model). This represents the HTML page as a tree with nodes that can be manipulated via the JavaScript DOM API.

For example, you can [](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector)[query for elements with `Document.querySelector()`](https://developer.mozilla.org/en-US/docs/Web/API/Document_object_model/Locating_DOM_elements_using_selectors), change their [style by setting the `HTMLElement.style` property](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style), add [event listeners with `EventTarget.addEventListener`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) to detect clicks/hovers/etc, and much more!

## Bringing the `/` shortcut to any site

With some basic knowledge of the DOM API, we can now easily bring the `/` shortcut to any site by creating a small userscript:

1.  Install a userscript manager.  
    Userscript managers let you see all your userscripts in one place, and most have a built-in web editor so you can edit scripts within your browser. [Tampermonkey](https://www.tampermonkey.net/) is a popular userscript manager, and is available for almost all browsers.  
    
2.  Create a new userscript.  
    There will be a new extension button for your userscript manager with an option similar to "Create a new script":

    ![Tampermonkey browser extension 'Create a new script' button](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wobp0caftnsehh6j2hy3.png)

3.  Write your userscript code:

```
// ==UserScript==
// @name         '/' search bar focus
// @description  Focus search bar on SLASH press
// @version      0.1
// @match        *://*/*
// ==/UserScript==

(function() {
    window.addEventListener("keypress", e => {
        if (['TEXTAREA', 'INPUT'].includes(e.target.nodeName)) return;
        if (e.key !== "/") return;
        
        const searchField = document.querySelector('textarea[type="search"], input[type="search"], input[name="search"], input[placeholder*="Search"]');
        if (!searchField) return;

        searchField.focus();
        searchField.setSelectionRange(searchField.value.length, searchField.value.length);
        e.preventDefault();
    });
})();
```

Note how the metadata block uses `// @match *://*/*`. This is because we want this particular script to run on _every_ page!

After the metadata block, we have our actual code. Tampermonkey by default suggests wrapping your code into an [IIFE (Immediately Invoked Function Expression)](https://developer.mozilla.org/en-US/docs/Glossary/IIFE). This is generally a good practice as it means we do not pollute the global namespace with our own variables, functions, etc.

The code adds a `keypress` [event listener](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) to the entire page. If the keypress is already within a `textarea` or `input` element, or is not the `/` key, the handler immediately returns. Otherwise, the first search field is found, focussed, and the cursor is moved to the end.

You can choose how you define a 'search' field, but some common aspects are that they have a `type=search` or `name=search` attribute. You can even use some more advanced [CSS attribute selectors](https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors) like `[attr*=value]` to find elements whose attribute just _contains_ a string (e.g., containing "search" somewhere in the `placeholder`).

**That's it! To test it out, you can try making e.g., [a Bing search](https://www.bing.com/search?q=test) and pressing the `/` key – you'll jump straight to the search bar!**