Tiny Project X: Chrome Command Bar

Soliudeen Ogunsola
Soliudeen Case Studies
7 min readAug 3, 2024

--

Navigate your browser like a pro with just a few clicks.

Photo by Addy Osmani on Unsplash

I’m a big fan of command-menu services like Raycast, Alfred App, and Spotlight by Command Bar. Creating a project like those has been on my to-do list, and today, I’m thrilled to share that my own command menu extension is now live on the Chrome Web Store.

About

The Chrome Command Bar extension is designed to enhance your productivity and streamline your browsing experience.

With just a few keystrokes, you can access a wide range of browser functions and popular websites. Navigate through the command list and hit Enter to execute your chosen action, all without touching your mouse.

Whether you need to open a new tab or incognito window, access browser settings or developer tools, or visit your favourite websites like GitHub, ChatGPT, Claude, Perplexity, or YouTube, everything is just a Cmd+K away.

Features

  • Keyboard shortcut (Ctrl+K or Cmd+K) to open the command bar.
  • Search functionality to quickly filter and find commands.
  • Various browser actions like opening new tabs, incognito windows, reloading pages, etc.
  • Quick access to Chrome settings, developer tools, and built-in pages.
  • Shortcuts to popular websites and services (e.g., ChatGPT, GitHub, Claude).
  • Ability to copy the current page URL and generate QR codes.

How It Works

  • Install the Chrome Command Bar extension from the Chrome Web Store.
  • Press Ctrl+K (or Cmd+K on Mac) to open the command palette.
  • Start typing to filter the command list.
  • Use the arrow keys to navigate and Enter to execute a command.

Demo

I recorded a short video to show how the Chrome Command Bar extension works.

Chrome Command Bar — Demo

Design

I designed the command bar UI to have a white background color, a grey outline, and dimensions of 640px by 540px. I added a search input with a list of command action items, each with an icon and its corresponding action text. Each icon has a width and height of 20px. The font size of the text is 14px, with a grey color.

Chrome Command Bar — UI

Development

This extension was built using HTML, CSS, and JavaScript, like all the previous ones I have published.

File Structure

This is how the extension files looks in VS Code.

chromecommandbar/
├── icons/
├── background.js
├── manifest.json
├── popup.html
├── popup.js
└── styles.css

Manifest

Themanifest.json file is an important component of any Chrome extension. It provides important metadata about the extension and defines its capabilities. Some notable parts of this file are:

“permissions”: [“activeTab”, “tabs”, “scripting”, “clipboardWrite”]

  • “activeTab” allows the extension to access the current active tab.
  • “tabs” allows the extension to interact with the browser’s tab system.
  • “scripting” allows the extension to run scripts in web pages.
  • “clipboardWrite” allows the extension to write to the clipboard.

“host_permissions”: [“<all_urls>”]

  • This gives the extension permission to run on all websites.
  • It’s necessary for features like copying the current page URL.

“action”: {“default_popup”: “popup.html”}

  • This specifies that when the extension icon is clicked, it should open popup.html.

“background”: {“service_worker”: “background.js”}

  • This defines background.js as the extension’s service worker.
  • The service worker runs in the background and can handle events even when the pop-up is closed.

“commands”: {…}

  • This section defines keyboard shortcuts for the extension.
  • It sets up Ctrl+K (or Command+K on Mac) as a shortcut to open the extension’s popup.
  • The “_execute_action” key is a special command that refers to the action of opening the popup.

The file sets up the extension’s identity, defines its required permissions, specifies its core components (popup and background script), and sets up a keyboard shortcut. It’s the blueprint that Chrome uses to understand how to load and run the extension.

Background Script

The background.js file acts as the behind-the-scenes worker for the Chrome extension. Here’s what it does:

It sets up a listener for messages from other parts of the extension, like the popup.

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {...});

When it receives a message, it looks at the ‘action’ specified in the message and performs the corresponding task. These tasks include:

  • Opening a new tab.
  • Opening a new incognito window.
  • Reloading the current tab.
  • Copying the current page’s link to the clipboard.
  • Creating a QR code for the current page.
  • Opening various Chrome pages (like DevTools, Extensions, Bookmarks, History, etc.).
  • Opening specific websites (like ChatGPT, Claude, WhatsApp, GitHub, etc.).

For most actions, it uses Chrome’s built-in APIs to perform the task. For example:

  • chrome.tabs.create()to open a new tab.
  • chrome.windows.create()to open a new window.
  • chrome.tabs.reload()to reload a tab.
    switch (request.action) {
case 'newTab':
chrome.tabs.create({});
break;
case 'newIncognito':
chrome.windows.create({ incognito: true });
break;
case 'reload':
chrome.tabs.reload();
break;
// Other actions goes here
}

ThecopyLink action does something more complex:

  • It finds the current active tab.
  • It injects and executes a script in that tab to copy the URL to the clipboard.
  • It then sends a response back to whoever sent the message, indicating success or failure.
 case 'copyLink':
// Copy the current page URL to clipboard
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
// Create a temporary textarea, copy the URL, and remove the textarea
chrome.scripting.executeScript({
target: { tabId: tabs[0].id },
func: (url) => {
const textArea = document.createElement("textarea");
textArea.value = url;
document.body.appendChild(textArea);
textArea.select();
document.execCommand("copy");
document.body.removeChild(textArea);
return true; // Indicate success
},
args: [tabs[0].url]
}, (results) => {
// Handle the response
if (chrome.runtime.lastError) {
sendResponse({ success: false, error: chrome.runtime.lastError.message });
} else if (results && results[0] && results[0].result === true) {
sendResponse({ success: true });
} else {
sendResponse({ success: false, error: "Unknown error occurred" });
}
});
});

For actions that open specific websites, it simply creates a new tab with the appropriate URL.

        case 'claude':
chrome.tabs.create({ url: 'https://www.claude.ai' });
break;

The script essentially acts as a central command centre, receiving instructions from the popup and carrying them out using Chrome’s APIs.

Popup Script

Thepopup.js file controls the behaviour of the popup that appears when you click the extension icon or use the keyboard shortcut. Here’s what it does:

It waits for the pop-up’s HTML to fully load before running its code.

document.addEventListener('DOMContentLoaded', function () {...});

It sets up references to important elements in the popup, like the search input and the list of commands.

    const commandList = document.getElementById('command-list');
const searchInput = document.getElementById('search-input');
let selectedIndex = -1;

It defines several helper functions:

  • selectItem()visually highlights a selected item in the list.
    function selectItem(index) {
const items = getVisibleItems();
items.forEach(item => item.classList.remove('selected'));
if (index >= 0 && index < items.length) {
items[index].classList.add('selected');
items[index].scrollIntoView({ block: 'nearest' });
}
}
  • getVisibleItems()gets all the items in the list that aren’t hidden.
    function getVisibleItems() {
return Array.from(commandList.querySelectorAll('li:not([style*="display: none"])'));
}
  • performAction()sends a message to the background script to perform an action.
    function performAction(action) {
chrome.runtime.sendMessage({ action: action });
}

It sets up event listeners for user interactions:

  • Clicking on an item in the list: This sends a message to the background script to perform the selected action.
    commandList.addEventListener('click', function (e) {
const action = e.target.closest('li').dataset.action;
if (action) {
chrome.runtime.sendMessage({ action: action }, function (response) {
if (action === 'copyLink') {
if (response && response.success) {
alert('Page link copied to clipboard!');
} else {
alert('Failed to copy page link. ' + (response.error || ''));
}
}
window.close(); // Close the popup after action is performed
});
}
});
  • Typing in the search box: This filters the list of commands based on what the user types.
    searchInput.addEventListener('input', function () {
const filter = this.value.toLowerCase();
const items = commandList.querySelectorAll('li');
items.forEach(item => {
const text = item.textContent.toLowerCase();
item.style.display = text.includes(filter) ? '' : 'none';
});
selectedIndex = -1;
selectItem(selectedIndex);
});

// Set focus to the search input when the popup opens
searchInput.focus();
  • Using arrow keys: This allows the user to navigate the list using their keyboard.
  • Pressing Enter: This performs the selected action.
  • Pressing Escape: This closes the popup.
    searchInput.addEventListener('keydown', function (e) {
const items = getVisibleItems();
if (e.key === 'ArrowDown') {
e.preventDefault();
selectedIndex = (selectedIndex + 1) % items.length;
selectItem(selectedIndex);
} else if (e.key === 'ArrowUp') {
e.preventDefault();
selectedIndex = (selectedIndex - 1 + items.length) % items.length;
selectItem(selectedIndex);
} else if (e.key === 'Enter') {
e.preventDefault();
if (selectedIndex >= 0) {
performAction(items[selectedIndex].dataset.action);
}
} else if (e.key === 'Escape') {
window.close();
}
});

The search functionality works by hiding list items that don’t match the search term and showing ones that do. It automatically focuses the search input when the popup opens, so the user can start typing immediately.

When an action is performed, it sends a message to the background script and then closes the popup.

It also handles the special case of thecopyLink action, showing an alert to the user about whether the copy was successful.

The popup script makes the command bar interactive and user-friendly, allowing quick access to all its features through both mouse and keyboard interactions.

Availability

The Chrome Command Bar extension has been published and is available for installation on the Chrome Web Store. You can easily add it to your Chrome browser now to browse like a pro with just a few clicks.

Credits

I couldn’t have completed this extension without Claude’s assistance throughout the development process. A big shoutout to the service.

Hi, thanks for reading this piece! I’m Soliudeen Ogunsola. If you find this article interesting and want to connect with me, you can follow me on X (formerly known as Twitter) or check me out on LinkedIn.

--

--