Search Bar in a Firefox New Tab Extension: Which Engine, How to Handle
Adding a search bar to a new tab extension sounds simple — it's just a text input and a redirect. But there are enough details to get right that it's worth writing down.
The Basic Implementation
<form id="search-form" role="search">
<input
type="search"
id="search-input"
placeholder="Search..."
autocomplete="off"
autofocus
/>
</form>
document.getElementById('search-form').addEventListener('submit', e => {
e.preventDefault();
const query = document.getElementById('search-input').value.trim();
if (query) {
window.location.href = buildSearchUrl(query);
}
});
Supporting Multiple Search Engines
const SEARCH_ENGINES = {
google: {
name: 'Google',
url: 'https://www.google.com/search?q=',
icon: '🔍'
},
duckduckgo: {
name: 'DuckDuckGo',
url: 'https://duckduckgo.com/?q=',
icon: '🦆'
},
bing: {
name: 'Bing',
url: 'https://www.bing.com/search?q=',
icon: '🔷'
},
brave: {
name: 'Brave Search',
url: 'https://search.brave.com/search?q=',
icon: '🦁'
},
startpage: {
name: 'Startpage',
url: 'https://www.startpage.com/search?q=',
icon: '🔒'
},
};
function buildSearchUrl(query, engine = 'google') {
const { url } = SEARCH_ENGINES[engine] || SEARCH_ENGINES.google;
return url + encodeURIComponent(query);
}
Keyboard Shortcut: Focus Search on Any Key
For power users — pressing any letter key should focus the search bar:
document.addEventListener('keydown', e => {
// Don't steal focus if user is typing in another input
if (document.activeElement.tagName === 'INPUT') return;
if (document.activeElement.tagName === 'TEXTAREA') return;
// Skip special keys
if (e.ctrlKey || e.metaKey || e.altKey) return;
if (e.key.length !== 1) return; // Skip Shift, Enter, etc.
const searchInput = document.getElementById('search-input');
searchInput.focus();
// Don't prevent default — let the keystroke go into the input
});
URL Detection: Smart Redirect
Users often type URLs into search bars. Detect and redirect directly:
function isUrl(input) {
// Has a dot and no spaces -> likely a URL
if (!input.includes('.') || input.includes(' ')) return false;
// Check known TLDs
const tldPattern = /\.(com|net|org|io|dev|co|app|ai|me|uk|de|fr|ca|au)(\/.*)?$/i;
if (tldPattern.test(input)) return true;
// Has http(s):// prefix
if (/^https?:\/\//i.test(input)) return true;
return false;
}
function buildSearchUrl(query, engine = 'google') {
if (isUrl(query)) {
// Navigate directly to URL
if (/^https?:\/\//i.test(query)) return query;
return 'https://' + query;
}
const { url } = SEARCH_ENGINES[engine] || SEARCH_ENGINES.google;
return url + encodeURIComponent(query);
}
Open in New Tab vs Same Tab
Let users decide:
document.getElementById('search-form').addEventListener('submit', e => {
e.preventDefault();
const query = document.getElementById('search-input').value.trim();
if (!query) return;
const url = buildSearchUrl(query, currentEngine);
if (openInNewTab) {
window.open(url, '_blank');
} else {
window.location.href = url;
}
});
// Also handle Ctrl+Enter for "new tab" regardless of setting
document.getElementById('search-input').addEventListener('keydown', e => {
if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) {
e.preventDefault();
const query = e.target.value.trim();
if (query) window.open(buildSearchUrl(query), '_blank');
}
});
Search Suggestions (Optional)
For DuckDuckGo, there's a free suggestions API:
async function getSuggestions(query) {
if (query.length < 2) return [];
try {
const resp = await fetch(
`https://duckduckgo.com/ac/?q=${encodeURIComponent(query)}&type=list`
);
const [, suggestions] = await resp.json();
return suggestions.slice(0, 5);
} catch {
return [];
}
}
Note: This requires host_permissions for https://duckduckgo.com/ in your manifest.
Accessibility
Don't forget:
<form role="search" aria-label="Web search">
<label for="search-input" class="visually-hidden">Search the web</label>
<input
type="search"
id="search-input"
aria-label="Search query"
placeholder="Search or enter address"
/>
<button type="submit" aria-label="Search">
<svg><!-- search icon --></svg>
</button>
</form>
What Engine to Default To?
I use Google as default in Weather & Clock Dashboard because it's what most users expect. But DuckDuckGo is a close second for privacy-conscious users, and it's trivially changeable in settings.
The key principle: match the user's existing habits. A new tab extension is productivity infrastructure — it should disappear into the workflow, not require relearning.
Weather & Clock Dashboard — free Firefox new tab with search, weather, and clocks. MIT licensed, no tracking.
Top comments (0)