UI Components Easy
Keyboard Shortcuts Overlay
GitHub-style keyboard shortcuts cheat sheet overlay triggered by pressing the question mark key with categorized shortcut listings.
Open in Lab
MCP
vanilla-js css
Targets: JS HTML
Code
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background: #0a0a0a;
color: #e5e5e5;
min-height: 100vh;
}
/* โโ App Layout โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.app {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.app-header {
display: flex;
align-items: center;
gap: 24px;
padding: 0 24px;
height: 56px;
background: #111;
border-bottom: 1px solid #222;
}
.app-logo {
display: flex;
align-items: center;
gap: 10px;
font-weight: 700;
font-size: 0.95rem;
color: #f5f5f5;
flex-shrink: 0;
}
.app-nav {
display: flex;
gap: 4px;
flex: 1;
}
.nav-link {
padding: 6px 14px;
border-radius: 6px;
font-size: 0.85rem;
font-weight: 500;
color: #888;
text-decoration: none;
transition: background 0.15s, color 0.15s;
}
.nav-link:hover {
background: #1a1a1a;
color: #ccc;
}
.nav-link.active {
background: #1e1e2e;
color: #e5e5e5;
}
.app-actions {
flex-shrink: 0;
}
.hint-badge {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 12px;
background: #161616;
border: 1px solid #2a2a2a;
border-radius: 8px;
font-size: 0.78rem;
color: #777;
cursor: pointer;
transition: border-color 0.2s, color 0.2s;
}
.hint-badge:hover {
border-color: #444;
color: #aaa;
}
.hint-badge kbd {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 22px;
height: 20px;
padding: 0 5px;
background: #1a1a1a;
border: 1px solid #333;
border-bottom-width: 2px;
border-radius: 4px;
font-family: inherit;
font-size: 0.7rem;
font-weight: 700;
color: #bbb;
}
/* โโ App Main โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.app-main {
display: flex;
flex: 1;
}
.app-sidebar {
width: 220px;
padding: 24px 20px;
border-right: 1px solid #1a1a1a;
flex-shrink: 0;
}
.sidebar-title {
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: #555;
margin-bottom: 12px;
}
.sidebar-list {
list-style: none;
}
.sidebar-list li a {
display: block;
padding: 7px 12px;
border-radius: 6px;
font-size: 0.85rem;
color: #888;
text-decoration: none;
transition: background 0.15s, color 0.15s;
}
.sidebar-list li a:hover {
background: #161616;
color: #ccc;
}
.app-content {
flex: 1;
padding: 32px 40px;
}
.content-title {
font-size: 1.5rem;
font-weight: 700;
color: #f5f5f5;
margin-bottom: 8px;
}
.content-text {
font-size: 0.9rem;
color: #888;
line-height: 1.6;
margin-bottom: 28px;
}
.content-text kbd {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 22px;
height: 20px;
padding: 0 5px;
background: #1a1a1a;
border: 1px solid #333;
border-bottom-width: 2px;
border-radius: 4px;
font-family: inherit;
font-size: 0.7rem;
font-weight: 700;
color: #bbb;
}
/* โโ Cards โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
gap: 16px;
margin-bottom: 28px;
}
.stat-card {
display: flex;
flex-direction: column;
gap: 4px;
padding: 20px;
background: #111;
border: 1px solid #222;
border-radius: 12px;
}
.stat-value {
font-size: 1.5rem;
font-weight: 700;
color: #f5f5f5;
}
.stat-label {
font-size: 0.78rem;
color: #666;
font-weight: 500;
}
/* โโ Search โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.search-bar-container {
max-width: 480px;
}
.search-bar {
width: 100%;
padding: 10px 16px;
background: #111;
border: 1px solid #262626;
border-radius: 10px;
font-size: 0.85rem;
color: #e5e5e5;
transition: border-color 0.2s;
}
.search-bar::placeholder {
color: #555;
}
.search-bar:focus {
outline: none;
border-color: #6366f1;
}
/* โโ Overlay โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.overlay-backdrop {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
opacity: 0;
visibility: hidden;
transition: opacity 0.2s, visibility 0.2s;
}
.overlay-backdrop.open {
opacity: 1;
visibility: visible;
}
.overlay {
width: 90%;
max-width: 700px;
max-height: 80vh;
display: flex;
flex-direction: column;
background: #141414;
border: 1px solid #2a2a2a;
border-radius: 16px;
box-shadow: 0 24px 64px rgba(0, 0, 0, 0.6);
transform: scale(0.96) translateY(10px);
transition: transform 0.2s;
}
.overlay-backdrop.open .overlay {
transform: scale(1) translateY(0);
}
.overlay-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px 28px 16px;
border-bottom: 1px solid #222;
}
.overlay-title {
font-size: 1.1rem;
font-weight: 700;
color: #f5f5f5;
}
.overlay-close {
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
background: transparent;
border: none;
border-radius: 6px;
color: #666;
cursor: pointer;
transition: background 0.15s, color 0.15s;
}
.overlay-close:hover {
background: #222;
color: #ccc;
}
.overlay-close:focus-visible {
outline: 2px solid #6366f1;
outline-offset: -2px;
}
.overlay-body {
flex: 1;
overflow-y: auto;
padding: 20px 28px;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 28px;
}
.overlay-footer {
padding: 14px 28px;
border-top: 1px solid #222;
text-align: center;
font-size: 0.78rem;
color: #555;
}
.overlay-footer kbd {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 20px;
height: 18px;
padding: 0 5px;
background: #1a1a1a;
border: 1px solid #333;
border-bottom-width: 2px;
border-radius: 4px;
font-family: inherit;
font-size: 0.65rem;
font-weight: 700;
color: #bbb;
}
/* โโ Shortcut Categories โโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
.shortcut-category {
display: flex;
flex-direction: column;
gap: 10px;
}
.category-title {
font-size: 0.8rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.06em;
color: #6366f1;
margin-bottom: 4px;
}
.shortcut-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
.shortcut-keys {
display: flex;
align-items: center;
gap: 4px;
flex-shrink: 0;
}
.shortcut-keys kbd {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 28px;
height: 28px;
padding: 0 8px;
background: #1a1a1a;
border: 1px solid #333;
border-bottom-width: 3px;
border-radius: 6px;
font-family: inherit;
font-size: 0.75rem;
font-weight: 700;
color: #d4d4d4;
line-height: 1;
}
.shortcut-keys .key-plus {
font-size: 0.7rem;
color: #555;
font-weight: 400;
}
.shortcut-desc {
font-size: 0.82rem;
color: #888;
text-align: right;
}
/* โโ Responsive โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
@media (max-width: 640px) {
.app-sidebar {
display: none;
}
.overlay-body {
grid-template-columns: 1fr;
gap: 20px;
}
.app-header {
padding: 0 16px;
}
.app-content {
padding: 24px 20px;
}
}(() => {
const backdrop = document.getElementById("overlayBackdrop");
const overlay = document.getElementById("overlay");
const overlayBody = document.getElementById("overlayBody");
const overlayClose = document.getElementById("overlayClose");
const hintBadge = document.getElementById("hintBadge");
/* โโ Shortcuts Data โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
const shortcuts = [
{
category: "Navigation",
items: [
{ keys: ["g", "h"], desc: "Go to Home" },
{ keys: ["g", "p"], desc: "Go to Projects" },
{ keys: ["g", "s"], desc: "Go to Settings" },
{ keys: ["g", "n"], desc: "Go to Notifications" },
],
},
{
category: "Actions",
items: [
{ keys: ["c"], desc: "Create new item" },
{ keys: ["e"], desc: "Edit selected" },
{ keys: ["Ctrl", "Enter"], desc: "Submit form" },
{ keys: ["Ctrl", "s"], desc: "Save changes" },
{ keys: ["d"], desc: "Delete selected" },
],
},
{
category: "Search",
items: [
{ keys: ["/"], desc: "Focus search bar" },
{ keys: ["Ctrl", "k"], desc: "Command palette" },
{ keys: ["Esc"], desc: "Clear search / Close" },
],
},
{
category: "Help",
items: [
{ keys: ["?"], desc: "Show this overlay" },
{ keys: ["Ctrl", "/"], desc: "Toggle sidebar" },
{ keys: ["Ctrl", "."], desc: "Toggle dark mode" },
],
},
];
/* โโ Render Shortcuts โโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
function renderShortcuts() {
overlayBody.innerHTML = "";
shortcuts.forEach((cat) => {
const section = document.createElement("div");
section.className = "shortcut-category";
const title = document.createElement("h3");
title.className = "category-title";
title.textContent = cat.category;
section.appendChild(title);
cat.items.forEach((item) => {
const row = document.createElement("div");
row.className = "shortcut-row";
const keysDiv = document.createElement("div");
keysDiv.className = "shortcut-keys";
item.keys.forEach((key, i) => {
const kbd = document.createElement("kbd");
kbd.textContent = key;
keysDiv.appendChild(kbd);
if (i < item.keys.length - 1) {
const plus = document.createElement("span");
plus.className = "key-plus";
plus.textContent = "+";
keysDiv.appendChild(plus);
}
});
const desc = document.createElement("span");
desc.className = "shortcut-desc";
desc.textContent = item.desc;
row.appendChild(keysDiv);
row.appendChild(desc);
section.appendChild(row);
});
overlayBody.appendChild(section);
});
}
renderShortcuts();
/* โโ Open / Close โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
let triggerElement = null;
function openOverlay() {
triggerElement = document.activeElement;
backdrop.classList.add("open");
backdrop.setAttribute("aria-hidden", "false");
// Focus the close button
requestAnimationFrame(() => overlayClose.focus());
}
function closeOverlay() {
backdrop.classList.remove("open");
backdrop.setAttribute("aria-hidden", "true");
// Restore focus
if (triggerElement && triggerElement.focus) {
triggerElement.focus();
}
}
function isOverlayOpen() {
return backdrop.classList.contains("open");
}
/* โโ Event Listeners โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
// Global "?" key listener
document.addEventListener("keydown", (e) => {
// Ignore if inside input/textarea/contenteditable
const tag = e.target.tagName.toLowerCase();
const isEditable = tag === "input" || tag === "textarea" || e.target.isContentEditable;
if (e.key === "?" && !isEditable) {
e.preventDefault();
if (isOverlayOpen()) {
closeOverlay();
} else {
openOverlay();
}
return;
}
if (e.key === "Escape" && isOverlayOpen()) {
e.preventDefault();
closeOverlay();
}
});
// Close button
overlayClose.addEventListener("click", closeOverlay);
// Hint badge
hintBadge.addEventListener("click", () => {
if (isOverlayOpen()) {
closeOverlay();
} else {
openOverlay();
}
});
// Click backdrop to close
backdrop.addEventListener("click", (e) => {
if (e.target === backdrop) {
closeOverlay();
}
});
// Trap focus inside overlay when open
overlay.addEventListener("keydown", (e) => {
if (e.key !== "Tab") return;
const focusable = overlay.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
const first = focusable[0];
const last = focusable[focusable.length - 1];
if (e.shiftKey) {
if (document.activeElement === first) {
e.preventDefault();
last.focus();
}
} else {
if (document.activeElement === last) {
e.preventDefault();
first.focus();
}
}
});
})();<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Keyboard Shortcuts Overlay</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<!-- Sample app page -->
<div class="app" id="app">
<header class="app-header">
<div class="app-logo">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/></svg>
<span>WorkspaceApp</span>
</div>
<nav class="app-nav">
<a href="#" class="nav-link active">Dashboard</a>
<a href="#" class="nav-link">Projects</a>
<a href="#" class="nav-link">Settings</a>
</nav>
<div class="app-actions">
<button class="hint-badge" id="hintBadge" aria-label="Show keyboard shortcuts">
Press <kbd>?</kbd> for shortcuts
</button>
</div>
</header>
<main class="app-main">
<div class="app-sidebar">
<h3 class="sidebar-title">Quick Links</h3>
<ul class="sidebar-list">
<li><a href="#">Recent files</a></li>
<li><a href="#">Starred items</a></li>
<li><a href="#">Shared with me</a></li>
<li><a href="#">Trash</a></li>
</ul>
</div>
<div class="app-content">
<h1 class="content-title">Dashboard</h1>
<p class="content-text">This is a sample application to demonstrate the keyboard shortcuts overlay. Press <kbd>?</kbd> anywhere (outside a text field) to open the shortcuts cheat sheet.</p>
<div class="card-grid">
<div class="stat-card">
<span class="stat-value">142</span>
<span class="stat-label">Active Projects</span>
</div>
<div class="stat-card">
<span class="stat-value">28</span>
<span class="stat-label">Team Members</span>
</div>
<div class="stat-card">
<span class="stat-value">96%</span>
<span class="stat-label">Uptime</span>
</div>
<div class="stat-card">
<span class="stat-value">3.2k</span>
<span class="stat-label">Deployments</span>
</div>
</div>
<div class="search-bar-container">
<input type="text" class="search-bar" placeholder="Search projects, files, settings…" aria-label="Search" />
</div>
</div>
</main>
</div>
<!-- Shortcuts Overlay -->
<div class="overlay-backdrop" id="overlayBackdrop" aria-hidden="true">
<div class="overlay" role="dialog" aria-label="Keyboard shortcuts" id="overlay">
<div class="overlay-header">
<h2 class="overlay-title">Keyboard Shortcuts</h2>
<button class="overlay-close" id="overlayClose" aria-label="Close shortcuts overlay">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
</button>
</div>
<div class="overlay-body" id="overlayBody">
<!-- Categories injected by JS -->
</div>
<div class="overlay-footer">
<span>Press <kbd>?</kbd> or <kbd>Esc</kbd> to close</span>
</div>
</div>
</div>
<script src="script.js"></script>
</body>
</html>A GitHub-inspired keyboard shortcuts cheat sheet that appears as a frosted-glass overlay when the user presses the โ?โ key. Shortcuts are organized into categories with styled key-cap elements for a polished, informative experience.