Keyboard Shortcuts in Firefox Extensions: A Complete Guide
Keyboard shortcuts make extensions feel native. A new tab extension that users can control without clicking feels much more polished. Here's how to add them to your Firefox extension.
Declaring Commands in manifest.json
{
"manifest_version": 2,
"commands": {
"toggle-dark-mode": {
"suggested_key": {
"default": "Ctrl+Shift+D",
"mac": "Command+Shift+D"
},
"description": "Toggle dark/light mode"
},
"refresh-weather": {
"suggested_key": {
"default": "Ctrl+Shift+R"
},
"description": "Refresh weather data"
},
"_execute_browser_action": {
"suggested_key": {
"default": "Ctrl+Shift+W",
"mac": "Command+Shift+W"
}
}
}
}
The special _execute_browser_action command opens your extension's popup.
Handling Commands in Background Script
// background.js
browser.commands.onCommand.addListener((command) => {
switch (command) {
case 'toggle-dark-mode':
toggleDarkMode();
break;
case 'refresh-weather':
refreshWeatherData();
break;
}
});
async function toggleDarkMode() {
const { theme } = await browser.storage.local.get('theme');
const newTheme = theme === 'dark' ? 'light' : 'dark';
await browser.storage.local.set({ theme: newTheme });
// Notify all open new tab pages
const tabs = await browser.tabs.query({ url: 'about:newtab' });
tabs.forEach(tab => {
browser.tabs.sendMessage(tab.id, { type: 'theme-changed', theme: newTheme })
.catch(() => {}); // Tab might not have content script
});
}
Keyboard Shortcuts Within the New Tab Page
For shortcuts that only work within your new tab page, use regular DOM event listeners:
// newtab.js
document.addEventListener('keydown', (e) => {
// Ignore when user is typing in a text field
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return;
switch (e.key) {
case 'd':
case 'D':
if (!e.ctrlKey && !e.metaKey) toggleDarkMode();
break;
case 'r':
case 'R':
if (!e.ctrlKey && !e.metaKey) refreshWeather();
break;
case '/':
// Focus the search bar
e.preventDefault();
document.getElementById('search-input')?.focus();
break;
case 'Escape':
// Blur search, close any open dropdowns
document.activeElement?.blur();
closeAllDropdowns();
break;
}
});
Showing Available Shortcuts to Users
A quick help modal makes shortcuts discoverable:
// Show keyboard shortcuts modal with ? key
document.addEventListener('keydown', (e) => {
if (e.key === '?' && !e.ctrlKey && !e.metaKey) {
toggleShortcutsModal();
}
});
function toggleShortcutsModal() {
const modal = document.getElementById('shortcuts-modal');
if (!modal) {
createShortcutsModal();
} else {
modal.classList.toggle('hidden');
}
}
function createShortcutsModal() {
const shortcuts = [
{ key: '/', description: 'Focus search' },
{ key: 'D', description: 'Toggle dark mode' },
{ key: 'R', description: 'Refresh weather' },
{ key: 'Esc', description: 'Clear focus' },
{ key: '?', description: 'Show this help' },
];
const modal = document.createElement('div');
modal.id = 'shortcuts-modal';
modal.innerHTML = `
<div class="shortcuts-overlay" onclick="this.parentElement.classList.add('hidden')"></div>
<div class="shortcuts-content">
<h3>Keyboard Shortcuts</h3>
<table>
${shortcuts.map(s => `
<tr>
<td><kbd>${s.key}</kbd></td>
<td>${s.description}</td>
</tr>
`).join('')}
</table>
<p class="shortcuts-note">Ctrl+Shift+D — Toggle dark mode (works from any tab)</p>
</div>
`;
document.body.appendChild(modal);
}
CSS for the kbd element
kbd {
display: inline-block;
padding: 2px 6px;
font-size: 12px;
font-family: monospace;
border: 1px solid rgba(255, 255, 255, 0.3);
border-radius: 3px;
background: rgba(255, 255, 255, 0.1);
box-shadow: 0 1px 1px rgba(0,0,0,0.2);
}
.dark-mode kbd {
border-color: rgba(255,255,255,0.2);
background: rgba(255,255,255,0.1);
}
Managing Commands in code (MV3)
In Manifest V3, you can update command shortcuts programmatically:
// Get all registered commands
const commands = await browser.commands.getAll();
commands.forEach(cmd => {
console.log(cmd.name, cmd.shortcut, cmd.description);
});
// Reset to default
await browser.commands.reset('toggle-dark-mode');
Conflict Avoidance Tips
-
Avoid single letters as
Ctrl+Lettershortcuts — many are already taken (Ctrl+R = refresh, Ctrl+T = new tab, etc.) -
Use three-key combos like
Ctrl+Shift+Dfor global shortcuts -
Single letter shortcuts within the page (like
/for search) are fine when you skip text inputs - Check for conflicts at about:addons → Manage Extension Shortcuts
The Keyboard Shortcut Settings Page
Users can view and change extension shortcuts at:
about:addons → gear icon → Manage Extension Shortcuts
Link directly to it from your extension's options page:
// Opens about:addons in a new tab, then user navigates to shortcuts
browser.tabs.create({ url: 'about:addons' });
The Weather & Clock Dashboard uses the / shortcut to focus the search bar — one of the most-used features.
Top comments (0)