Toggle navigation
☰
Home
HTML
CSS
Scripting
Database
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>The Command Palette Navbar</title> <style> :root { --color-background: #f9fafb; --color-text: #1f2937; --color-text-muted: #6b7280; --color-primary: #3b82f6; --color-border: #e5e7eb; --color-surface: #ffffff; --color-overlay-bg: rgba(23, 23, 25, 0.6); --font-family-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; --navbar-height: 70px; --palette-width: 640px; --border-radius: 12px; } *, *::before, *::after { box-sizing: border-box; } body { margin: 0; font-family: var(--font-family-sans); background-color: var(--color-background); color: var(--color-text); } .content { min-height: 150vh; padding: 1.5rem; max-width: 1024px; margin: 0 auto; } body.cmd-palette-open { overflow: hidden; } .visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0, 0, 0, 0); border: 0; } /* Navbar Styles */ .navbar { height: var(--navbar-height); display: flex; align-items: center; background-color: var(--color-surface); border-bottom: 1px solid var(--color-border); } .navbar__container { display: flex; align-items: center; justify-content: space-between; width: 100%; max-width: 1024px; margin: 0 auto; padding: 0 1.5rem; } .navbar__brand { font-size: 1.5rem; font-weight: 600; } .cmd-palette-trigger { display: flex; align-items: center; gap: .75rem; padding: .5rem .75rem; border: 1px solid var(--color-border); border-radius: 8px; background-color: var(--color-background); cursor: pointer; color: var(--color-text-muted); } .kbd-shortcut { background-color: #fff; padding: .125rem .375rem; border-radius: 4px; border: 1px solid var(--color-border); border-bottom-width: 2px; font-size: 0.75rem; color: var(--color-text-primary); } /* Command Palette Overlay and Modal */ .cmd-palette { position: fixed; inset: 0; z-index: 2000; display: flex; justify-content: center; align-items: flex-start; background-color: var(--color-overlay-bg); padding-top: 15vh; /* Hide/Show logic */ opacity: 0; visibility: hidden; transition: opacity 0.2s, visibility 0.2s; } .cmd-palette.is-open { opacity: 1; visibility: visible; } .cmd-palette__modal { width: 100%; max-width: var(--palette-width); background-color: var(--color-surface); border-radius: var(--border-radius); box-shadow: 0 10px 30px rgba(0,0,0,0.2); transition: transform 0.2s; transform: scale(0.95); } .cmd-palette.is-open .cmd-palette__modal { transform: scale(1); } .cmd-palette__header { display: flex; align-items: center; gap: 1rem; padding: .75rem; border-bottom: 1px solid var(--color-border); } .cmd-palette__input { flex-grow: 1; border: none; background: transparent; font-size: 1.1rem; width: 100%; } .cmd-palette__input:focus { outline: none; } .cmd-palette__results { max-height: 40vh; overflow-y: auto; padding: .5rem; } .cmd-palette__item { display: block; width: 100%; text-align: left; padding: .75rem; border-radius: 6px; background: none; border: none; cursor: pointer; font-size: 1rem; color: var(--color-text); } .cmd-palette__item:hover, .cmd-palette__item.is-highlighted { background-color: var(--color-primary); color: #fff; } .cmd-palette__item[aria-disabled="true"] { color: var(--color-text-muted); background-color: var(--color-surface); pointer-events: none; } </style> </head> <body> <header class="navbar"> <div class="navbar__container"> <a href="#" class="navbar__brand">PowerApp</a> <button class="cmd-palette-trigger" id="cmd-palette-trigger" aria-haspopup="dialog" aria-controls="cmd-palette"> Search or jump to... <kbd class="kbd-shortcut" aria-hidden="true"> <span class="cmd-key">⌘</span>K </kbd> </button> </div> </header> <div class="cmd-palette" id="cmd-palette" role="dialog" aria-modal="true" aria-labelledby="cmd-palette-label" tabindex="-1"> <div class="cmd-palette__modal"> <h2 id="cmd-palette-label" class="visually-hidden">Command Palette</h2> <div class="cmd-palette__header"> <svg width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M9.5,3A6.5,6.5 0 0,1 16,9.5C16,11.11 15.41,12.59 14.44,13.73L14.71,14H15.5L20.5,19L19,20.5L14,15.5V14.71L13.73,14.44C12.59,15.41 11.11,16 9.5,16A6.5,6.5 0 0,1 3,9.5A6.5,6.5 0 0,1 9.5,3M9.5,5C7,5 5,7 5,9.5C5,12 7,14 9.5,14C12,14 14,12 14,9.5C14,7 12,5 9.5,5Z"></path></svg> <input class="cmd-palette__input" id="cmd-palette-input" type="text" placeholder="Type a command or search..." role="combobox" aria-expanded="true" aria-controls="cmd-palette-results"> </div> <ul class="cmd-palette__results" id="cmd-palette-results" role="listbox"> <!-- Results will be dynamically rendered here --> </ul> </div> </div> <main class="content"> <h1>Command Palette Navbar</h1> <p>Click the search button or press <code>⌘K</code> (or <code>Ctrl+K</code> on Windows) to open the palette.</p> </main> <script> document.addEventListener('DOMContentLoaded', () => { // --- 1. Data Source --- // In a real app, this might come from an API or be generated const commandItems = [ { name: 'Dashboard', href: '#dashboard', section: 'Navigation' }, { name: 'Analytics', href: '#analytics', section: 'Navigation' }, { name: 'Reports', href: '#reports', section: 'Navigation' }, { name: 'Create New Project', action: () => alert('Creating project...'), section: 'Actions' }, { name: 'Invite User', action: () => alert('Inviting user...'), section: 'Actions' }, { name: 'API Settings', href: '#settings-api', section: 'Settings' }, { name: 'Billing', href: '#settings-billing', section: 'Settings' } ]; // --- 2. Element References --- const triggerButton = document.getElementById('cmd-palette-trigger'); const palette = document.getElementById('cmd-palette'); const input = document.getElementById('cmd-palette-input'); const resultsList = document.getElementById('cmd-palette-results'); const cmdKeySpan = document.querySelector('.cmd-key'); let highlightedIndex = -1; // --- 3. Core Functions --- function openPalette() { // Adapt shortcut hint for non-Mac users if (!navigator.platform.includes('Mac')) { cmdKeySpan.textContent = 'Ctrl'; } renderResults(commandItems); palette.classList.add('is-open'); document.body.classList.add('cmd-palette-open'); input.focus(); } function closePalette() { palette.classList.remove('is-open'); document.body.classList.remove('cmd-palette-open'); input.value = ''; // Clear input on close triggerButton.focus(); // Restore focus } function renderResults(items) { resultsList.innerHTML = ''; let lastSection = null; if(items.length === 0) { resultsList.innerHTML = '<li><button class="cmd-palette__item" aria-disabled="true">No results found</button></li>'; return; } items.forEach((item, index) => { // Add section headers if(item.section !== lastSection) { const sectionHeader = document.createElement('li'); sectionHeader.innerHTML = `<button class="cmd-palette__item" aria-disabled="true">${item.section}</button>`; resultsList.appendChild(sectionHeader); lastSection = item.section; } const li = document.createElement('li'); li.innerHTML = `<button class="cmd-palette__item" data-index="${index}">${item.name}</button>`; li.querySelector('button').addEventListener('click', () => { executeCommand(item); }); resultsList.appendChild(li); }); highlightedIndex = 0; // Highlight the first actual command updateHighlight(); } function executeCommand(item) { closePalette(); if (item.href) window.location.href = item.href; if (item.action) item.action(); } function updateHighlight() { const items = resultsList.querySelectorAll('.cmd-palette__item:not([aria-disabled="true"])'); items.forEach((item, index) => { if (index === highlightedIndex) item.classList.add('is-highlighted'); else item.classList.remove('is-highlighted'); }); } // --- 4. Event Listeners --- triggerButton.addEventListener('click', openPalette); palette.addEventListener('click', (e) => { // Close on overlay click if(e.target === palette) closePalette(); }); document.addEventListener('keydown', (e) => { // Open with Ctrl/Cmd + K if ((e.metaKey || e.ctrlKey) && e.key === 'k') { e.preventDefault(); openPalette(); } if (e.key === 'Escape') closePalette(); // Handle arrow navigation when palette is open if (palette.classList.contains('is-open')) { const commandButtons = Array.from(resultsList.querySelectorAll('.cmd-palette__item:not([aria-disabled="true"])')); if(commandButtons.length === 0) return; if (e.key === 'ArrowDown') { e.preventDefault(); highlightedIndex = (highlightedIndex + 1) % commandButtons.length; updateHighlight(); } else if (e.key === 'ArrowUp') { e.preventDefault(); highlightedIndex = (highlightedIndex - 1 + commandButtons.length) % commandButtons.length; updateHighlight(); } else if (e.key === 'Enter') { e.preventDefault(); const highlightedItemName = commandButtons[highlightedIndex]?.textContent; const originalItem = commandItems.find(item => item.name === highlightedItemName); if (originalItem) executeCommand(originalItem); } } }); input.addEventListener('input', () => { const query = input.value.toLowerCase(); const filteredItems = commandItems.filter(item => item.name.toLowerCase().includes(query)); renderResults(filteredItems); }); }); </script> </body> </html>