SaaS — Global Command Bar (⌘K)
A polished, accessible global command bar overlay for SaaS apps, opened with Cmd-K or Ctrl-K. It pairs a search input with grouped results for Navigation, Actions, Recent, and Settings, plus fuzzy matching with highlighted hits, full keyboard navigation via arrows, Enter and Esc, a focus trap, action icons and shortcut hints, a working dark-theme toggle, and a recent-commands list that updates as you go. Built with vanilla JS, no libraries.
MCP
Code
:root {
--bg: #f7f8fb;
--surface: #ffffff;
--surface-2: #f1f2f7;
--ink: #0f1222;
--muted: #646b85;
--faint: #8b91a8;
--brand: #6366f1;
--brand-d: #4f46e5;
--brand-soft: rgba(99, 102, 241, .1);
--ok: #16a34a;
--warn: #d97706;
--danger: #dc2626;
--line: rgba(15, 18, 34, .1);
--line-2: rgba(15, 18, 34, .06);
--shadow-lg: 0 24px 60px -12px rgba(15, 18, 34, .28), 0 8px 24px -8px rgba(15, 18, 34, .14);
--radius: 14px;
--hl: #fde68a;
}
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
margin: 0;
font-family: "Inter", system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
background: var(--bg);
color: var(--ink);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
:focus-visible {
outline: 2px solid var(--brand);
outline-offset: 2px;
border-radius: 6px;
}
kbd.kbd {
display: inline-flex;
align-items: center;
gap: 1px;
font-family: inherit;
font-size: 11px;
font-weight: 600;
line-height: 1;
padding: 3px 6px;
border-radius: 6px;
background: var(--surface-2);
border: 1px solid var(--line);
color: var(--muted);
box-shadow: 0 1px 0 var(--line);
}
.kbd--inline { padding: 2px 5px; transform: translateY(-1px); }
.kbd__cmd { font-size: 12px; }
.kbd--ghost {
background: transparent;
border-color: var(--line-2);
box-shadow: none;
padding: 2px 6px;
}
/* ---------- App shell ---------- */
.app { min-height: 100vh; display: flex; flex-direction: column; }
.topbar {
display: flex;
align-items: center;
gap: 16px;
padding: 14px 24px;
background: var(--surface);
border-bottom: 1px solid var(--line);
position: sticky;
top: 0;
z-index: 5;
}
.brand { display: flex; align-items: center; gap: 8px; }
.brand__mark {
display: grid; place-items: center;
width: 32px; height: 32px;
border-radius: 9px;
color: #fff;
background: linear-gradient(140deg, var(--brand), var(--brand-d));
box-shadow: 0 4px 12px -4px var(--brand);
}
.brand__name { font-weight: 700; font-size: 16px; letter-spacing: -.01em; }
.brand__tag {
font-size: 11px; font-weight: 600; color: var(--muted);
background: var(--surface-2); padding: 3px 8px; border-radius: 999px;
}
.searchTrigger {
margin-left: auto;
display: flex;
align-items: center;
gap: 10px;
width: min(420px, 42vw);
padding: 9px 12px;
font: inherit;
font-size: 14px;
color: var(--faint);
background: var(--bg);
border: 1px solid var(--line);
border-radius: 10px;
cursor: pointer;
transition: border-color .15s, background .15s, box-shadow .15s;
}
.searchTrigger:hover { border-color: var(--brand); background: var(--surface); box-shadow: 0 0 0 4px var(--brand-soft); }
.searchTrigger svg { color: var(--faint); flex: none; }
.searchTrigger span { flex: 1; text-align: left; }
.searchTrigger .kbd { margin-left: auto; }
.avatar {
margin-left: 4px;
width: 34px; height: 34px;
display: grid; place-items: center;
border-radius: 50%;
font-size: 13px; font-weight: 600; color: #fff;
background: linear-gradient(135deg, #f97316, #db2777);
flex: none;
}
.content { padding: 40px 24px 64px; max-width: 1040px; width: 100%; margin: 0 auto; }
.content h1 { font-size: 28px; letter-spacing: -.02em; margin: 0 0 6px; }
.lede { color: var(--muted); margin: 0 0 28px; font-size: 15px; max-width: 60ch; }
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
gap: 16px;
}
.card {
display: flex; flex-direction: column; gap: 6px;
padding: 18px;
background: var(--surface);
border: 1px solid var(--line);
border-radius: var(--radius);
box-shadow: 0 1px 2px var(--line-2);
}
.card__label { font-size: 12px; font-weight: 600; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.card__value { font-size: 26px; font-weight: 700; letter-spacing: -.02em; }
.card__delta { font-size: 12px; font-weight: 600; color: var(--faint); }
.card__delta--up { color: var(--ok); }
.card__delta--down { color: var(--danger); }
/* ---------- Command bar ---------- */
.cmdk {
position: fixed;
inset: 0;
z-index: 50;
display: flex;
justify-content: center;
align-items: flex-start;
padding: clamp(40px, 12vh, 120px) 16px 16px;
}
.cmdk[hidden] { display: none; }
.cmdk__backdrop {
position: absolute;
inset: 0;
background: rgba(15, 18, 34, .42);
backdrop-filter: blur(3px);
animation: fade .14s ease;
}
.cmdk__panel {
position: relative;
width: min(620px, 100%);
background: var(--surface);
border: 1px solid var(--line);
border-radius: 16px;
box-shadow: var(--shadow-lg);
overflow: hidden;
display: flex;
flex-direction: column;
max-height: min(70vh, 560px);
animation: pop .16s cubic-bezier(.2, .9, .3, 1.2);
}
@keyframes fade { from { opacity: 0; } }
@keyframes pop { from { opacity: 0; transform: translateY(-8px) scale(.985); } }
.cmdk__searchRow {
display: flex;
align-items: center;
gap: 12px;
padding: 14px 16px;
border-bottom: 1px solid var(--line);
}
.cmdk__searchIcon { color: var(--faint); flex: none; }
.cmdk__input {
flex: 1;
font: inherit;
font-size: 16px;
border: none;
background: transparent;
color: var(--ink);
padding: 2px 0;
}
.cmdk__input:focus { outline: none; }
.cmdk__input::placeholder { color: var(--faint); }
.cmdk__esc {
font: inherit; font-size: 11px; font-weight: 600;
color: var(--muted);
background: var(--surface-2);
border: 1px solid var(--line);
border-radius: 6px;
padding: 4px 8px;
cursor: pointer;
}
.cmdk__esc:hover { color: var(--ink); border-color: var(--brand); }
.cmdk__list {
list-style: none;
margin: 0;
padding: 8px;
overflow-y: auto;
flex: 1;
scroll-padding: 8px;
}
.cmdk__group {
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: .06em;
color: var(--faint);
padding: 12px 10px 6px;
}
.cmdk__group:first-child { padding-top: 6px; }
.cmdk__item {
display: flex;
align-items: center;
gap: 12px;
padding: 10px 10px;
border-radius: 10px;
cursor: pointer;
color: var(--ink);
scroll-margin: 8px;
}
.cmdk__item[aria-selected="true"] { background: var(--brand-soft); }
.cmdk__item[aria-selected="true"] .cmdk__icon { color: var(--brand-d); border-color: var(--brand); }
.cmdk__item[aria-selected="true"] .cmdk__go { opacity: 1; }
.cmdk__icon {
flex: none;
width: 30px; height: 30px;
display: grid; place-items: center;
border-radius: 8px;
background: var(--surface-2);
border: 1px solid var(--line-2);
color: var(--muted);
font-size: 15px;
}
.cmdk__body { flex: 1; min-width: 0; }
.cmdk__title {
font-size: 14px; font-weight: 500;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cmdk__sub { font-size: 12px; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cmdk__title mark { background: var(--hl); color: inherit; border-radius: 3px; padding: 0 1px; font-weight: 700; }
.cmdk__shortcut { display: flex; gap: 4px; flex: none; }
.cmdk__go {
flex: none; color: var(--brand-d); opacity: 0; font-size: 14px;
transition: opacity .12s;
}
.cmdk__empty {
padding: 40px 24px 48px;
text-align: center;
color: var(--muted);
}
.cmdk__emptyIcon { font-size: 30px; display: block; margin-bottom: 8px; filter: grayscale(.3); }
.cmdk__empty p { margin: 4px 0; font-size: 14px; }
.cmdk__empty p:first-of-type { color: var(--ink); font-weight: 500; }
.cmdk__emptyHint { color: var(--faint); font-size: 12px; }
.cmdk__footer {
display: flex;
align-items: center;
gap: 14px;
padding: 10px 14px;
border-top: 1px solid var(--line);
background: var(--surface-2);
font-size: 12px;
color: var(--muted);
}
.cmdk__legend { display: inline-flex; align-items: center; gap: 5px; }
.cmdk__footerSpacer { flex: 1; }
.cmdk__legendBrand { font-weight: 600; color: var(--faint); }
/* ---------- Toast ---------- */
.toast {
position: fixed;
left: 50%;
bottom: 28px;
transform: translate(-50%, 12px);
z-index: 80;
display: flex;
align-items: center;
gap: 10px;
padding: 12px 18px;
background: var(--ink);
color: #fff;
font-size: 14px;
font-weight: 500;
border-radius: 12px;
box-shadow: var(--shadow-lg);
opacity: 0;
transition: opacity .2s, transform .2s;
max-width: calc(100vw - 32px);
}
.toast[hidden] { display: none; }
.toast.show { opacity: 1; transform: translate(-50%, 0); }
.toast__dot {
width: 8px; height: 8px; border-radius: 50%;
background: var(--brand); flex: none;
box-shadow: 0 0 0 4px var(--brand-soft);
}
@media (max-width: 560px) {
.topbar { gap: 10px; padding: 12px 16px; flex-wrap: wrap; }
.brand__tag { display: none; }
.searchTrigger { width: 100%; order: 3; }
.searchTrigger span { font-size: 13px; }
.content { padding: 28px 16px 48px; }
.content h1 { font-size: 23px; }
.cmdk__footer { gap: 10px; }
.cmdk__legend:nth-child(2) { display: none; }
}
@media (prefers-reduced-motion: reduce) {
.cmdk__panel, .cmdk__backdrop, .toast { animation: none; transition: none; }
}(function () {
"use strict";
// ---------- Command registry ----------
// group, title, subtitle, icon (emoji), keywords, shortcut keys, action
var COMMANDS = [
// Navigation
{ id: "nav-dashboard", group: "Navigation", title: "Go to Dashboard", sub: "Overview & metrics", icon: "📊", keys: ["G", "D"], kw: "home overview metrics" },
{ id: "nav-customers", group: "Navigation", title: "Go to Customers", sub: "Accounts & seats", icon: "👥", keys: ["G", "C"], kw: "accounts users people" },
{ id: "nav-billing", group: "Navigation", title: "Go to Billing", sub: "Plans, invoices, usage", icon: "💳", keys: ["G", "B"], kw: "invoices payments plan subscription" },
{ id: "nav-analytics", group: "Navigation", title: "Go to Analytics", sub: "Funnels & retention", icon: "📈", keys: ["G", "A"], kw: "reports charts funnel retention" },
{ id: "nav-integrations", group: "Navigation", title: "Go to Integrations", sub: "Webhooks & API keys", icon: "🔌", keys: ["G", "I"], kw: "api webhooks connections" },
// Actions
{ id: "act-invite", group: "Actions", title: "Invite teammate", sub: "Send a seat invitation", icon: "✉️", keys: ["⌘", "I"], kw: "add member user seat email" },
{ id: "act-new-project", group: "Actions", title: "Create new project", sub: "Spin up a workspace", icon: "✨", keys: ["⌘", "N"], kw: "add create workspace" },
{ id: "act-export", group: "Actions", title: "Export data as CSV", sub: "Download current view", icon: "⬇️", keys: ["⌘", "E"], kw: "download csv report data" },
{ id: "act-key", group: "Actions", title: "Generate API key", sub: "Create a new secret key", icon: "🔑", keys: [], kw: "token secret api credentials" },
{ id: "act-status", group: "Actions", title: "View system status", sub: "Uptime & incidents", icon: "🟢", keys: [], kw: "uptime incident health" },
// Settings
{ id: "set-theme", group: "Settings", title: "Toggle dark theme", sub: "Switch appearance", icon: "🌗", keys: ["⌘", "."], kw: "dark light appearance mode color" },
{ id: "set-profile", group: "Settings", title: "Edit profile", sub: "Name, avatar, email", icon: "🙍", keys: [], kw: "account name avatar me" },
{ id: "set-notifications", group: "Settings", title: "Notification preferences", sub: "Email & in-app alerts", icon: "🔔", keys: [], kw: "alerts email push" },
{ id: "set-security", group: "Settings", title: "Security & 2FA", sub: "Sessions and MFA", icon: "🛡️", keys: [], kw: "password mfa two factor sessions" }
];
var GROUP_ORDER = ["Recent", "Navigation", "Actions", "Settings"];
// ---------- DOM ----------
var overlay = document.getElementById("cmdk");
var panel = overlay.querySelector(".cmdk__panel");
var input = document.getElementById("cmdkInput");
var list = document.getElementById("cmdkList");
var empty = document.getElementById("cmdkEmpty");
var emptyTerm = document.getElementById("cmdkEmptyTerm");
var openBtn = document.getElementById("openBar");
var toastEl = document.getElementById("toast");
var recentIds = ["nav-billing", "act-invite"]; // seed recents
var visible = []; // flat list of currently rendered command objects (in order)
var activeIndex = 0;
var lastFocused = null;
var dark = false;
// ---------- Fuzzy matching ----------
// Returns { score, ranges } where ranges are [start,end) over the title, or null.
function fuzzy(query, cmd) {
if (!query) return { score: 0, ranges: [] };
var q = query.toLowerCase();
var title = cmd.title;
var lt = title.toLowerCase();
var hay = (lt + " " + cmd.kw).toLowerCase();
// substring in title -> best, with highlight ranges
var sub = lt.indexOf(q);
if (sub !== -1) {
return { score: 1000 - sub + (sub === 0 ? 50 : 0), ranges: [[sub, sub + q.length]] };
}
// substring anywhere in keywords -> good, no title highlight
if (hay.indexOf(q) !== -1) {
return { score: 500, ranges: [] };
}
// subsequence over title -> fuzzy, collect char ranges
var ti = 0, qi = 0, ranges = [], runStart = -1, gaps = 0;
while (ti < lt.length && qi < q.length) {
if (lt[ti] === q[qi]) {
if (runStart === -1) runStart = ti;
qi++;
ti++;
if (qi === q.length || lt[ti] !== q[qi]) {
ranges.push([runStart, ti]);
runStart = -1;
}
} else {
if (runStart !== -1) { ranges.push([runStart, ti]); runStart = -1; }
ti++;
gaps++;
}
}
if (qi === q.length) return { score: 200 - gaps, ranges: ranges };
return null;
}
function highlight(title, ranges) {
if (!ranges || !ranges.length) return escapeHtml(title);
var out = "";
var cur = 0;
ranges.forEach(function (r) {
out += escapeHtml(title.slice(cur, r[0]));
out += "<mark>" + escapeHtml(title.slice(r[0], r[1])) + "</mark>";
cur = r[1];
});
out += escapeHtml(title.slice(cur));
return out;
}
function escapeHtml(s) {
return s.replace(/[&<>"]/g, function (c) {
return { "&": "&", "<": "<", ">": ">", '"': """ }[c];
});
}
// ---------- Render ----------
function render(query) {
var results = [];
if (!query) {
// default view: recents first, then everything by group order
recentIds.forEach(function (id) {
var c = COMMANDS.find(function (x) { return x.id === id; });
if (c) results.push({ cmd: c, group: "Recent", ranges: [], score: 0 });
});
COMMANDS.forEach(function (c) {
results.push({ cmd: c, group: c.group, ranges: [], score: 0 });
});
} else {
COMMANDS.forEach(function (c) {
var m = fuzzy(query, c);
if (m) results.push({ cmd: c, group: c.group, ranges: m.ranges, score: m.score });
});
results.sort(function (a, b) { return b.score - a.score; });
}
list.innerHTML = "";
visible = [];
if (!results.length) {
emptyTerm.textContent = query;
empty.hidden = false;
list.hidden = true;
input.setAttribute("aria-expanded", "false");
return;
}
empty.hidden = true;
list.hidden = false;
input.setAttribute("aria-expanded", "true");
// group while preserving sort order: when searching keep score order but
// still label groups; for default view, bucket by GROUP_ORDER.
var rendered = [];
if (!query) {
GROUP_ORDER.forEach(function (g) {
results.filter(function (r) { return r.group === g; })
.forEach(function (r) { rendered.push(r); });
});
} else {
rendered = results;
}
var lastGroup = null;
rendered.forEach(function (r) {
if (r.group !== lastGroup) {
var head = document.createElement("li");
head.className = "cmdk__group";
head.setAttribute("role", "presentation");
head.textContent = r.group;
list.appendChild(head);
lastGroup = r.group;
}
var idx = visible.length;
visible.push(r.cmd);
var li = document.createElement("li");
li.className = "cmdk__item";
li.id = "cmdk-opt-" + idx;
li.setAttribute("role", "option");
li.dataset.index = String(idx);
var keysHtml = r.cmd.keys.map(function (k) {
return '<kbd class="kbd kbd--ghost">' + escapeHtml(k) + "</kbd>";
}).join("");
li.innerHTML =
'<span class="cmdk__icon" aria-hidden="true">' + r.cmd.icon + "</span>" +
'<span class="cmdk__body">' +
'<span class="cmdk__title">' + highlight(r.cmd.title, r.ranges) + "</span>" +
'<span class="cmdk__sub">' + escapeHtml(r.cmd.sub) + "</span>" +
"</span>" +
(keysHtml ? '<span class="cmdk__shortcut">' + keysHtml + "</span>" : "") +
'<span class="cmdk__go" aria-hidden="true">↵</span>';
li.addEventListener("click", function () { runCommand(idx); });
li.addEventListener("mousemove", function () { setActive(idx, false); });
list.appendChild(li);
});
activeIndex = 0;
setActive(0, true);
}
function setActive(i, scroll) {
if (!visible.length) return;
activeIndex = (i + visible.length) % visible.length;
var items = list.querySelectorAll(".cmdk__item");
items.forEach(function (el) { el.setAttribute("aria-selected", "false"); });
var el = list.querySelector('.cmdk__item[data-index="' + activeIndex + '"]');
if (el) {
el.setAttribute("aria-selected", "true");
input.setAttribute("aria-activedescendant", el.id);
if (scroll) el.scrollIntoView({ block: "nearest" });
}
}
function move(delta) {
setActive(activeIndex + delta, true);
}
// ---------- Actions ----------
function runCommand(i) {
var cmd = visible[i];
if (!cmd) return;
// bump recents (max 4, dedupe)
recentIds = [cmd.id].concat(recentIds.filter(function (x) { return x !== cmd.id; })).slice(0, 4);
if (cmd.id === "set-theme") {
toggleTheme();
} else if (cmd.group === "Navigation") {
toast("Navigated → " + cmd.title.replace(/^Go to /, ""));
} else {
toast(cmd.icon + " " + cmd.title);
}
close();
}
function toggleTheme() {
dark = !dark;
var root = document.documentElement;
if (dark) {
root.style.setProperty("--bg", "#0d0f1a");
root.style.setProperty("--surface", "#161a2b");
root.style.setProperty("--surface-2", "#1e2236");
root.style.setProperty("--ink", "#f3f4fb");
root.style.setProperty("--muted", "#9aa1bd");
root.style.setProperty("--faint", "#6e7593");
root.style.setProperty("--line", "rgba(255,255,255,.12)");
root.style.setProperty("--line-2", "rgba(255,255,255,.07)");
root.style.setProperty("--brand-soft", "rgba(99,102,241,.2)");
toast("🌙 Dark theme on");
} else {
["--bg", "--surface", "--surface-2", "--ink", "--muted", "--faint", "--line", "--line-2", "--brand-soft"]
.forEach(function (p) { root.style.removeProperty(p); });
toast("☀️ Light theme on");
}
}
// ---------- Open / close ----------
function open() {
if (!overlay.hidden) return;
lastFocused = document.activeElement;
overlay.hidden = false;
input.value = "";
render("");
requestAnimationFrame(function () { input.focus(); });
}
function close() {
if (overlay.hidden) return;
overlay.hidden = true;
input.removeAttribute("aria-activedescendant");
if (lastFocused && lastFocused.focus) lastFocused.focus();
}
// ---------- Focus trap ----------
function trap(e) {
if (e.key !== "Tab") return;
var focusables = panel.querySelectorAll("input, button, [tabindex]:not([tabindex='-1'])");
if (!focusables.length) return;
var first = focusables[0];
var last = focusables[focusables.length - 1];
if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last.focus(); }
else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first.focus(); }
}
// ---------- Toast ----------
var toastTimer;
function toast(msg) {
clearTimeout(toastTimer);
toastEl.innerHTML = '<span class="toast__dot" aria-hidden="true"></span><span>' + escapeHtml(msg) + "</span>";
toastEl.hidden = false;
requestAnimationFrame(function () { toastEl.classList.add("show"); });
toastTimer = setTimeout(function () {
toastEl.classList.remove("show");
setTimeout(function () { toastEl.hidden = true; }, 220);
}, 2200);
}
// ---------- Events ----------
input.addEventListener("input", function () { render(input.value.trim()); });
document.addEventListener("keydown", function (e) {
// global open: ⌘K / Ctrl-K
if ((e.metaKey || e.ctrlKey) && (e.key === "k" || e.key === "K")) {
e.preventDefault();
overlay.hidden ? open() : close();
return;
}
if (overlay.hidden) return;
trap(e);
if (e.key === "Escape") { e.preventDefault(); close(); }
else if (e.key === "ArrowDown") { e.preventDefault(); move(1); }
else if (e.key === "ArrowUp") { e.preventDefault(); move(-1); }
else if (e.key === "Enter") { e.preventDefault(); runCommand(activeIndex); }
else if (e.key === "Home" && document.activeElement === input) { /* let caret move */ }
});
openBtn.addEventListener("click", open);
overlay.querySelectorAll("[data-close]").forEach(function (el) {
el.addEventListener("click", close);
});
})();<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Northwind — Global Command Bar</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;450;500;600;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="style.css" />
</head>
<body>
<!-- App shell (background context) -->
<div class="app" aria-hidden="false">
<header class="topbar" role="banner">
<div class="brand">
<span class="brand__mark" aria-hidden="true">
<svg viewBox="0 0 24 24" width="20" height="20" fill="none"><path d="M4 13.5 9 6l5 7.5M14 13.5 17 9l3 4.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>
</span>
<span class="brand__name">Northwind</span>
<span class="brand__tag">Console</span>
</div>
<button id="openBar" class="searchTrigger" aria-haspopup="dialog" aria-label="Open command bar">
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" aria-hidden="true"><circle cx="11" cy="11" r="7" stroke="currentColor" stroke-width="2"/><path d="m20 20-3-3" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
<span>Search or jump to…</span>
<kbd class="kbd"><span class="kbd__cmd">⌘</span>K</kbd>
</button>
<div class="avatar" title="Mara Okonjo" aria-label="Mara Okonjo">MO</div>
</header>
<main class="content" role="main">
<h1>Welcome back, Mara</h1>
<p class="lede">Your workspace at a glance. Press <kbd class="kbd kbd--inline"><span class="kbd__cmd">⌘</span>K</kbd> anywhere to navigate, run an action, or jump to settings.</p>
<section class="cards" aria-label="Workspace summary">
<article class="card"><span class="card__label">MRR</span><span class="card__value">$48,210</span><span class="card__delta card__delta--up">▲ 6.4%</span></article>
<article class="card"><span class="card__label">Active seats</span><span class="card__value">312</span><span class="card__delta card__delta--up">▲ 12</span></article>
<article class="card"><span class="card__label">Open tickets</span><span class="card__value">7</span><span class="card__delta card__delta--down">▼ 3</span></article>
<article class="card"><span class="card__label">Uptime 30d</span><span class="card__value">99.98%</span><span class="card__delta">stable</span></article>
</section>
</main>
</div>
<!-- Command bar overlay -->
<div id="cmdk" class="cmdk" hidden>
<div class="cmdk__backdrop" data-close></div>
<div class="cmdk__panel" role="dialog" aria-modal="true" aria-label="Command bar" aria-describedby="cmdk-hint">
<div class="cmdk__searchRow">
<svg class="cmdk__searchIcon" viewBox="0 0 24 24" width="18" height="18" fill="none" aria-hidden="true"><circle cx="11" cy="11" r="7" stroke="currentColor" stroke-width="2"/><path d="m20 20-3-3" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>
<input id="cmdkInput" class="cmdk__input" type="text" role="combobox"
aria-expanded="true" aria-controls="cmdkList" aria-autocomplete="list"
placeholder="Type a command or search…" autocomplete="off" spellcheck="false" />
<button class="cmdk__esc" data-close aria-label="Close command bar">Esc</button>
</div>
<ul id="cmdkList" class="cmdk__list" role="listbox" aria-label="Results"></ul>
<div id="cmdkEmpty" class="cmdk__empty" hidden>
<span class="cmdk__emptyIcon" aria-hidden="true">🔍</span>
<p>No results for “<span id="cmdkEmptyTerm"></span>”</p>
<p class="cmdk__emptyHint">Try “invite”, “billing”, or “theme”.</p>
</div>
<footer class="cmdk__footer" id="cmdk-hint">
<span class="cmdk__legend"><kbd class="kbd kbd--ghost">↑</kbd><kbd class="kbd kbd--ghost">↓</kbd> navigate</span>
<span class="cmdk__legend"><kbd class="kbd kbd--ghost">↵</kbd> select</span>
<span class="cmdk__legend"><kbd class="kbd kbd--ghost">esc</kbd> close</span>
<span class="cmdk__footerSpacer"></span>
<span class="cmdk__legendBrand">Northwind Console</span>
</footer>
</div>
</div>
<div id="toast" class="toast" role="status" aria-live="polite" hidden></div>
<script src="script.js"></script>
</body>
</html>Global Command Bar (⌘K)
A drop-in command palette for SaaS dashboards. Press ⌘K / Ctrl-K anywhere — or click the search field in the top bar — to summon a centered overlay with a focused search input and grouped results. Commands are organized into Recent, Navigation, Actions, and Settings, each row showing an icon, a subtitle, and keyboard-shortcut hints.
Typing runs a lightweight fuzzy matcher: it prefers title substrings, falls back to keyword matches, then to subsequence scoring, and highlights the matched characters inline. Navigation is fully keyboard-driven — ↑/↓ move the selection, Enter runs the highlighted command, and Esc closes the palette. The overlay traps focus while open and restores it to the trigger on close. Selecting a command fires a real demo action: navigation commands toast their destination, the theme command actually toggles a dark palette, and every choice is pushed onto the Recent list shown the next time you open the bar.
Everything is self-contained vanilla HTML, CSS, and JavaScript with no frameworks or external libraries, so you can lift the pattern straight into your own product shell.
Illustrative SaaS UI only — fictional product, metrics, and billing. No real backend.