Manage tabs

Build your first tabs manager.

Overview

This tutorial builds a tabs manager to organize your Chrome extension and Chrome Web store documentation tabs.

Tabs Manager extension popup
Tabs Manager extension

In this guide, we're going to explain how to do the following:

  • Create an extension popup using the Action API.
  • Query for specific tabs using the Tabs API.
  • Preserve user privacy through narrow host permissions.
  • Change the focus of the tab.
  • Move tabs to the same window and group them.
  • Rename tab groups using the TabGroups API.

Before you start

This guide assumes that you have basic web development experience. We recommend checking out Hello World for an introduction to the extension development workflow.

Build the extension

To start, create a new directory called tabs-manager to hold the extension's files. If you prefer, you can download the complete source code on GitHub.

Step 1: Add the extension data and icons

Create a file called manifest.json and add the following code:

{
  "manifest_version": 3,
  "name": "Tab Manager for Chrome Dev Docs",
  "version": "1.0",
  "icons": {
    "16": "images/icon-16.png",
    "32": "images/icon-32.png",
    "48": "images/icon-48.png",
    "128": "images/icon-128.png"
  }
}

To learn more about these manifest keys, check out the Reading time tutorial that explains the extension's metadata and icons in more detail.

Create an images folder then download the icons into it.

Step 2: Create and style the popup

The Action API controls the extension action (toolbar icon). When the user clicks on the extension action, it will either run some code or open a popup, like in this case. Start by declaring the popup in the manifest.json:

{
  "action": {
    "default_popup": "popup.html"
  }
}

A popup is similar to a web page with one exception: it can't run inline JavaScript. Create a popup.html file and add the following code:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="stylesheet" href="./popup.css" />
  </head>
  <body>
    <template id="li_template">
      <li>
        <a>
          <h3 class="title">Tab Title</h3>
          <p class="pathname">Tab Pathname</p>
        </a>
      </li>
    </template>

    <h1>Google Dev Docs</h1>
    <button>Group Tabs</button>
    <ul></ul>

    <script src="./popup.js" type="module"></script>
  </body>
</html>

Next, you'll style the popup. Create a popup.css file and add the following code:

body {
  width: 20rem;
}

ul {
  list-style-type: none;
  padding-inline-start: 0;
  margin: 1rem 0;
}

li {
  padding: 0.25rem;
}
li:nth-child(odd) {
  background: #80808030;
}
li:nth-child(even) {
  background: #ffffff;
}

h3,
p {
  margin: 0;
}

Step 3: Manage the tabs

The Tabs API allows an extension to create, query, modify, and rearrange tabs in the browser.

Request permission

Many methods in the Tabs API can be used without requesting any permission. However, we need access to the title and the URL of the tabs; these sensitive properties require permission. We could request "tabs" permission, but this would give access to the sensitive properties of all tabs. Since we are only managing tabs of a specific site, we will request narrow host permissions.

Narrow host permissions allow us to protect user privacy by granting elevated permission to specific sites. This will grant access to the title, and URL properties, as well as additional capabilities. Add the highlighted code to the manifest.json file:

{
  "host_permissions": [
    "https://developer.chrome.com/*"
  ]
}

💡 What are the main differences between the tabs permission and host permissions?

Both the "tabs" permission and host permissions have drawbacks.

The "tabs" permission grants an extension the ability to read sensitive data on all tabs. Over time, this information could be used to collect a user's browsing history. As such, if you request this permission Chrome will display the following warning message at install time:

Tabs permission warning dialog

Host permissions allow an extension to read and query a matching tab's sensitive properties, plus inject scripts on these tabs. Users will see the following warning message at install time:

Host permission warning dialog

These warning can be alarming for users. For a better onboarding experience, we recommend implementing optional permissions.

Query the tabs

You can retrieve the tabs from specific URLs using the tabs.query() method. Create a popup.js file and add the following code:

const tabs = await chrome.tabs.query({
  url: [
    "https://developer.chrome.com/docs/webstore/*",
    "https://developer.chrome.com/docs/extensions/*",
  ]
});

💡 Can I use Chrome APIs directly in the popup?

A popup and other extension pages can call any Chrome API because they are served from the chrome schema. For example chrome-extension://EXTENSION_ID/popup.html.

Focus on a tab

First, the extension will sort tab names (the titles of the contained HTML pages) alphabetically. Then, when a list item is clicked, it will focus on that tab using tabs.update() and bring the window to the front using windows.update(). Add the following code to the popup.js file:

...
const collator = new Intl.Collator();
tabs.sort((a, b) => collator.compare(a.title, b.title));

const template = document.getElementById("li_template");
const elements = new Set();
for (const tab of tabs) {
  const element = template.content.firstElementChild.cloneNode(true);

  const title = tab.title.split("-")[0].trim();
  const pathname = new URL(tab.url).pathname.slice("/docs".length);

  element.querySelector(".title").textContent = title;
  element.querySelector(".pathname").textContent = pathname;
  element.querySelector("a").addEventListener("click", async () => {
    // need to focus window as well as the active tab
    await chrome.tabs.update(tab.id, { active: true });
    await chrome.windows.update(tab.windowId, { focused: true });
  });

  elements.add(element);
}
document.querySelector("ul").append(...elements);
...

💡 Interesting JavaScript used in this code

  • The Collator used to sort the tabs array by the user's preferred language.
  • The template tag used to define an HTML element that can be cloned instead of using document.createElement() to create each item.
  • The URL constructor used to create and parse URLs.
  • The Spread syntax used to convert the Set of elements into arguments in the append() call.

Group the tabs

The TabGroups API allows the extension to name the group and choose a background color. Add the "tabGroups" permission to the manifest by adding the highlighted code:

{
  "permissions": [
    "tabGroups"
  ]
}

In popup.js, add the following code to create a button that will group all the tabs using tabs.group() and move them into the current window.

const button = document.querySelector("button");
button.addEventListener("click", async () => {
  const tabIds = tabs.map(({ id }) => id);
  if (tabIds.length) {
    const group = await chrome.tabs.group({ tabIds });
    await chrome.tabGroups.update(group, { title: "DOCS" });
  }
});

Test that it works

Verify that the file structure of your project matches the following directory tree:

The contents of the tabs manager folder: manifest.json, popup.js, popup.css, popup.html, and images folder.

Load your extension locally

To load an unpacked extension in developer mode, follow the steps in Hello World.

Open a few documentation pages

Open the following docs in different windows:

Click the popup. It should look like this:

Tabs Manager extension popup
Tabs Manager extension popup

Click the "Group tabs" button. It should look like this:

Tabs Manager Grouped tabs
Grouped tabs using the Tabs Manager extension

🎯 Potential enhancements

Based on what you've learned today, try to implement any of the following:

  • Customize the popup style sheet.
  • Change the color and title of the tab group.
  • Manage the tabs of another documentation site.
  • Add support for ungrouping the grouped tabs.

Keep building!

Congratulations on finishing this tutorial 🎉. Continue developing your skills by completing other tutorials on this series:

Extension What you will learn
Reading time To insert an element on every page automatically.
Focus Mode To run code on the current page after clicking on the extension action.

Continue exploring

We hope you enjoyed building this Chrome extension and are excited to continue your Chrome development learning journey. We recommend the following learning path:

  • The developer's guide has dozens of additional links to pieces of documentation relevant to advanced extension creation.
  • Extensions have access to powerful APIs beyond what's available on the open web. The Chrome APIs documentation walks through each API.