🔍 Search Bar Design Guide
Header search functionality є одним з найважливіших features для content-rich websites як mushroom education hub. Effective search bars allow users швидко знайти species information, cultivation guides, safety warnings, або research articles без navigating through menus. Цей comprehensive guide охоплює UX patterns, autocomplete implementation, search algorithms, та mobile optimization.
🎯 Search Bar Placement Options
1. Header Right (Recommended)
Pros:
- ✅ Standard web pattern (expected location)
- ✅ Always visible (sticky header)
- ✅ Doesn't compete з logo/nav
- ✅ Mobile: Can collapse до icon
Best for: Content sites, mushroom hub
2. Center Hero (Alternative)
Pros:
- ✅ Primary focus (e.g., Google)
- ✅ Large, prominent design
- ✅ Search-first experience
Best for: Search-driven platforms, databases
3. Expandable Icon
Pros:
- ✅ Saves space (minimal header)
- ✅ Clean aesthetic
- ✅ Mobile-friendly
Con: ❌ Hidden, lower discoverability
Mushroom Hub:
Recommendation: Header Right + Mobile Icon
- Desktop: Full search bar visible
- Mobile: 🔍 icon → expands full-width
- Always accessible у sticky header
🎨 Visual Design
Interactive Search Bar Demo
Design Specifications:
- Width: 300-400px (desktop), 100% (mobile expanded)
- Height: 44-48px (touch-friendly)
- Border radius: 20-25px (pill shape) або 8px (rounded square)
- Placeholder text: Descriptive, helpful examples
- Icon: 🔍 magnifying glass (22-24px)
- Colors: Light bg (#f8f9fa), dark text, accent border on focus
💻 Complete Implementation
HTML Structure:
<!-- Header Search Bar -->
<div class="header-search">
<form class="search-form" role="search" action="/search" method="GET">
<div class="search-input-wrapper">
<svg class="search-icon" width="20" height="20" viewBox="0 0 20 20">
<path d="M8 14A6 6 0 108 2a6 6 0 000 12zM14 14l4 4" stroke="currentColor" fill="none"/>
</svg>
<input
type="search"
name="q"
class="search-input"
placeholder="Search species, cultivation, safety..."
aria-label="Search mushroom knowledge base"
autocomplete="off"
spellcheck="false"
>
<button type="submit" class="search-submit" aria-label="Submit search">
Search
</button>
<button type="button" class="search-clear" aria-label="Clear search" style="display: none;">
<svg width="16" height="16" viewBox="0 0 16 16">
<path d="M12 4L4 12M4 4l8 8" stroke="currentColor"/>
</svg>
</button>
</div>
<!-- Autocomplete Dropdown -->
<div class="search-autocomplete" role="listbox" aria-label="Search suggestions">
<!-- Populated dynamically -->
</div>
</form>
</div>
CSS Styling:
.header-search {
position: relative;
max-width: 350px;
}
.search-input-wrapper {
position: relative;
display: flex;
align-items: center;
background: #f8f9fa;
border: 2px solid transparent;
border-radius: 25px;
transition: all 0.3s;
}
.search-input-wrapper:focus-within {
background: white;
border-color: #FF6B6B;
box-shadow: 0 4px 12px rgba(255, 107, 107, 0.15);
}
.search-icon {
position: absolute;
left: 15px;
color: #6c757d;
pointer-events: none;
}
.search-input {
flex: 1;
padding: 12px 100px 12px 45px;
border: none;
background: transparent;
font-size: 15px;
color: #2c3e50;
outline: none;
}
.search-input::placeholder {
color: #9ca3af;
}
.search-submit {
padding: 8px 20px;
background: #FF6B6B;
color: white;
border: none;
border-radius: 20px;
font-weight: 600;
cursor: pointer;
margin-right: 5px;
transition: background 0.2s;
}
.search-submit:hover {
background: #ff5252;
}
.search-clear {
position: absolute;
right: 110px;
background: transparent;
border: none;
cursor: pointer;
color: #6c757d;
padding: 5px;
display: flex;
align-items: center;
justify-content: center;
}
.search-clear:hover {
color: #FF6B6B;
}
/* Autocomplete Dropdown */
.search-autocomplete {
position: absolute;
top: calc(100% + 10px);
left: 0;
right: 0;
background: white;
border-radius: 12px;
box-shadow: 0 8px 30px rgba(0,0,0,0.15);
max-height: 400px;
overflow-y: auto;
display: none;
z-index: 1000;
}
.search-autocomplete.active {
display: block;
}
.autocomplete-item {
display: flex;
align-items: center;
padding: 12px 15px;
cursor: pointer;
border-bottom: 1px solid #f1f3f5;
transition: background 0.2s;
}
.autocomplete-item:hover,
.autocomplete-item.selected {
background: #fff4e6;
}
.autocomplete-item:last-child {
border-bottom: none;
}
.autocomplete-icon {
width: 20px;
height: 20px;
margin-right: 12px;
color: #6c757d;
}
.autocomplete-text {
flex: 1;
}
.autocomplete-title {
font-weight: 600;
color: #2c3e50;
}
.autocomplete-category {
font-size: 0.85em;
color: #6c757d;
margin-top: 2px;
}
/* Mobile Responsive */
@media (max-width: 768px) {
.header-search {
max-width: none;
}
.search-input-wrapper {
width: 100%;
}
.search-submit {
padding: 8px 15px;
font-size: 14px;
}
}
JavaScript Autocomplete:
// Search Implementation
class SearchBar {
constructor(containerSelector) {
this.container = document.querySelector(containerSelector);
this.input = this.container.querySelector('.search-input');
this.autocompleteEl = this.container.querySelector('.search-autocomplete');
this.clearBtn = this.container.querySelector('.search-clear');
// Search index (normally loaded від API)
this.searchIndex = [
{ title: 'Psilocybe cubensis', category: 'Species', url: '/species/cubensis' },
{ title: 'Safety Guidelines', category: 'Safety', url: '/safety' },
{ title: 'PF Tek Method', category: 'Cultivation', url: '/growing/pf-tek' },
// ... more items
];
this.selectedIndex = -1;
this.init();
}
init() {
// Input events
this.input.addEventListener('input', (e) => this.handleInput(e));
this.input.addEventListener('keydown', (e) => this.handleKeydown(e));
this.input.addEventListener('focus', () => this.showAutocomplete());
// Clear button
this.clearBtn.addEventListener('click', () => this.clearSearch());
// Close autocomplete on outside click
document.addEventListener('click', (e) => {
if (!this.container.contains(e.target)) {
this.hideAutocomplete();
}
});
}
handleInput(e) {
const query = e.target.value.trim();
// Show/hide clear button
this.clearBtn.style.display = query.length > 0 ? 'block' : 'none';
if (query.length < 2) {
this.hideAutocomplete();
return;
}
// Search
const results = this.search(query);
this.renderResults(results);
this.showAutocomplete();
}
search(query) {
const lowerQuery = query.toLowerCase();
return this.searchIndex
.filter(item => {
return item.title.toLowerCase().includes(lowerQuery) ||
item.category.toLowerCase().includes(lowerQuery);
})
.slice(0, 7); // Limit до 7 results
}
renderResults(results) {
if (results.length === 0) {
this.autocompleteEl.innerHTML = `
<div class="autocomplete-item">
<div class="autocomplete-text">
<div class="autocomplete-title">No results found</div>
</div>
</div>
`;
return;
}
this.autocompleteEl.innerHTML = results.map((item, index) => `
<a href="${item.url}" class="autocomplete-item" data-index="${index}">
<svg class="autocomplete-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path d="M9 12h6M12 9v6m9-9v12a2 2 0 01-2 2H5a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2z"/>
</svg>
<div class="autocomplete-text">
<div class="autocomplete-title">${this.highlightQuery(item.title, this.input.value)}</div>
<div class="autocomplete-category">${item.category}</div>
</div>
</a>
`).join('');
}
highlightQuery(text, query) {
const regex = new RegExp(`(${query})`, 'gi');
return text.replace(regex, '<strong>$1</strong>');
}
handleKeydown(e) {
const items = this.autocompleteEl.querySelectorAll('.autocomplete-item');
if (e.key === 'ArrowDown') {
e.preventDefault();
this.selectedIndex = Math.min(this.selectedIndex + 1, items.length - 1);
this.updateSelection(items);
} else if (e.key === 'ArrowUp') {
e.preventDefault();
this.selectedIndex = Math.max(this.selectedIndex - 1, 0);
this.updateSelection(items);
} else if (e.key === 'Enter' && this.selectedIndex >= 0) {
e.preventDefault();
items[this.selectedIndex].click();
} else if (e.key === 'Escape') {
this.hideAutocomplete();
}
}
updateSelection(items) {
items.forEach((item, index) => {
item.classList.toggle('selected', index === this.selectedIndex);
});
// Scroll into view
if (items[this.selectedIndex]) {
items[this.selectedIndex].scrollIntoView({ block: 'nearest' });
}
}
showAutocomplete() {
this.autocompleteEl.classList.add('active');
}
hideAutocomplete() {
this.autocompleteEl.classList.remove('active');
this.selectedIndex = -1;
}
clearSearch() {
this.input.value = '';
this.clearBtn.style.display = 'none';
this.hideAutocomplete();
this.input.focus();
}
}
// Initialize
document.addEventListener('DOMContentLoaded', () => {
new SearchBar('.header-search');
});
⚡ Advanced Features
1. Search History
Show recent searches коли input focused (empty state)
localStorage.setItem('searchHistory',
JSON.stringify(searches));
2. Category Filters
Quick filters below search bar:
- All Results
- Species
- Growing
- Safety
3. Voice Search
Web Speech API для voice input (modern browsers)
recognition.start();
4. Keyboard Shortcuts
Ctrl+K або Cmd+K to focus search
if (e.ctrlKey && e.key === 'k')
searchInput.focus();
✅ Search Bar Checklist
Implementation Checklist:
- ☐ Always visible у header (або icon на mobile)
- ☐ Autocomplete з ≥ 2 characters
- ☐ Keyboard navigation (arrows, Enter, Escape)
- ☐ Clear button (X) коли input has text
- ☐ Touch-friendly (≥ 44px height)
- ☐ ARIA labels для accessibility
- ☐ Search results highlight query
- ☐ Category badges у results
- ☐ Mobile: Full-width expansion
- ☐ Debounced API calls (300ms)
- ☐ Loading spinner during search
- ☐ "No results" state handled
- ☐ Keyboard shortcut (Ctrl+K)