UI Components Easy
Keyboard Shortcut Sheet
Keyboard shortcut cheat sheet with grouped categories, KBD key styling, and searchable filter. Pure CSS and minimal JS.
Open in Lab
MCP
vanilla-js css react tailwind vue svelte
Targets: TS JS HTML React Vue Svelte
Code
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
background: #f9fafb;
color: #111;
min-height: 100vh;
padding: 40px 24px;
display: flex;
justify-content: center;
}
.demo {
width: 100%;
max-width: 800px;
}
.ks-header {
display: flex;
align-items: center;
gap: 16px;
margin-bottom: 24px;
flex-wrap: wrap;
}
.ks-title {
font-size: 22px;
font-weight: 800;
flex: 1;
}
.ks-search {
padding: 9px 14px;
border: 1.5px solid #e5e7eb;
border-radius: 10px;
font-size: 14px;
outline: none;
width: 220px;
background: #fff;
color: #111;
transition: border-color 0.15s;
}
.ks-search:focus {
border-color: #6366f1;
}
.ks-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
}
@media (max-width: 640px) {
.ks-grid {
grid-template-columns: 1fr;
}
}
.ks-group {
background: #fff;
border: 1px solid #e5e7eb;
border-radius: 14px;
overflow: hidden;
}
.ks-group.hidden {
display: none;
}
.ks-group-title {
font-size: 11px;
font-weight: 700;
color: #6b7280;
text-transform: uppercase;
letter-spacing: 0.07em;
padding: 12px 16px 8px;
}
.ks-list {
display: flex;
flex-direction: column;
}
.ks-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 16px;
border-top: 1px solid #f3f4f6;
transition: background 0.12s;
}
.ks-item:hover {
background: #f9fafb;
}
.ks-item.hidden {
display: none;
}
.ks-desc {
font-size: 13px;
color: #374151;
}
.ks-desc mark {
background: #fef3c7;
border-radius: 2px;
padding: 0 1px;
}
.ks-keys {
display: flex;
align-items: center;
gap: 3px;
flex-shrink: 0;
}
.ks-plus {
font-size: 11px;
color: #9ca3af;
}
kbd {
display: inline-block;
background: #f3f4f6;
border: 1px solid #d1d5db;
border-bottom-width: 2px;
border-radius: 5px;
padding: 2px 6px;
font-size: 11px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
font-weight: 600;
color: #374151;
line-height: 1.4;
box-shadow: 0 1px 0 #d1d5db;
}
.ks-empty {
text-align: center;
padding: 48px 24px;
font-size: 15px;
color: #9ca3af;
}const search = document.getElementById("ksSearch");
const empty = document.getElementById("ksEmpty");
const emptyTerm = document.getElementById("ksEmptyTerm");
search.addEventListener("input", () => {
const q = search.value.trim().toLowerCase();
let anyVisible = false;
document.querySelectorAll(".ks-group").forEach((group) => {
let groupHasMatch = false;
group.querySelectorAll(".ks-item").forEach((item) => {
const desc = item.querySelector(".ks-desc");
const text = desc.textContent.toLowerCase();
const match = !q || text.includes(q);
item.classList.toggle("hidden", !match);
if (match) {
groupHasMatch = true;
if (q) {
// Highlight match
const idx = text.indexOf(q);
const raw = desc.textContent;
desc.innerHTML =
raw.slice(0, idx) +
`<mark>${raw.slice(idx, idx + q.length)}</mark>` +
raw.slice(idx + q.length);
} else {
desc.textContent = desc.textContent;
}
}
});
group.classList.toggle("hidden", !groupHasMatch);
if (groupHasMatch) anyVisible = true;
});
empty.hidden = anyVisible;
emptyTerm.textContent = q;
});<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Keyboard Shortcuts</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="demo">
<div class="ks-header">
<h1 class="ks-title">Keyboard Shortcuts</h1>
<input class="ks-search" id="ksSearch" type="search" placeholder="Search shortcuts…" />
</div>
<div class="ks-grid" id="ksGrid">
<div class="ks-group" data-group="navigation">
<h2 class="ks-group-title">Navigation</h2>
<div class="ks-list">
<div class="ks-item"><span class="ks-desc">Open command palette</span><div class="ks-keys"><kbd>⌘</kbd><kbd>K</kbd></div></div>
<div class="ks-item"><span class="ks-desc">Go to file</span><div class="ks-keys"><kbd>⌘</kbd><kbd>P</kbd></div></div>
<div class="ks-item"><span class="ks-desc">Go to line</span><div class="ks-keys"><kbd>⌃</kbd><kbd>G</kbd></div></div>
<div class="ks-item"><span class="ks-desc">Go back</span><div class="ks-keys"><kbd>⌃</kbd><kbd>-</kbd></div></div>
<div class="ks-item"><span class="ks-desc">Go forward</span><div class="ks-keys"><kbd>⌃</kbd><kbd>⇧</kbd><kbd>-</kbd></div></div>
<div class="ks-item"><span class="ks-desc">Switch tab</span><div class="ks-keys"><kbd>⌃</kbd><kbd>Tab</kbd></div></div>
</div>
</div>
<div class="ks-group" data-group="editing">
<h2 class="ks-group-title">Editing</h2>
<div class="ks-list">
<div class="ks-item"><span class="ks-desc">Save file</span><div class="ks-keys"><kbd>⌘</kbd><kbd>S</kbd></div></div>
<div class="ks-item"><span class="ks-desc">Undo</span><div class="ks-keys"><kbd>⌘</kbd><kbd>Z</kbd></div></div>
<div class="ks-item"><span class="ks-desc">Redo</span><div class="ks-keys"><kbd>⌘</kbd><kbd>⇧</kbd><kbd>Z</kbd></div></div>
<div class="ks-item"><span class="ks-desc">Cut line</span><div class="ks-keys"><kbd>⌘</kbd><kbd>X</kbd></div></div>
<div class="ks-item"><span class="ks-desc">Duplicate line</span><div class="ks-keys"><kbd>⌥</kbd><kbd>⇧</kbd><kbd>↓</kbd></div></div>
<div class="ks-item"><span class="ks-desc">Delete line</span><div class="ks-keys"><kbd>⌃</kbd><kbd>⇧</kbd><kbd>K</kbd></div></div>
<div class="ks-item"><span class="ks-desc">Toggle comment</span><div class="ks-keys"><kbd>⌘</kbd><kbd>/</kbd></div></div>
<div class="ks-item"><span class="ks-desc">Format document</span><div class="ks-keys"><kbd>⌥</kbd><kbd>⇧</kbd><kbd>F</kbd></div></div>
</div>
</div>
<div class="ks-group" data-group="selection">
<h2 class="ks-group-title">Selection</h2>
<div class="ks-list">
<div class="ks-item"><span class="ks-desc">Select all</span><div class="ks-keys"><kbd>⌘</kbd><kbd>A</kbd></div></div>
<div class="ks-item"><span class="ks-desc">Select word</span><div class="ks-keys"><kbd>⌘</kbd><kbd>D</kbd></div></div>
<div class="ks-item"><span class="ks-desc">Select all occurrences</span><div class="ks-keys"><kbd>⌘</kbd><kbd>⇧</kbd><kbd>L</kbd></div></div>
<div class="ks-item"><span class="ks-desc">Multi-cursor</span><div class="ks-keys"><kbd>⌥</kbd><span class="ks-plus">+</span>Click</div></div>
<div class="ks-item"><span class="ks-desc">Column select</span><div class="ks-keys"><kbd>⌥</kbd><kbd>⇧</kbd>Drag</div></div>
</div>
</div>
<div class="ks-group" data-group="search">
<h2 class="ks-group-title">Search & Replace</h2>
<div class="ks-list">
<div class="ks-item"><span class="ks-desc">Find</span><div class="ks-keys"><kbd>⌘</kbd><kbd>F</kbd></div></div>
<div class="ks-item"><span class="ks-desc">Replace</span><div class="ks-keys"><kbd>⌘</kbd><kbd>H</kbd></div></div>
<div class="ks-item"><span class="ks-desc">Find in files</span><div class="ks-keys"><kbd>⌘</kbd><kbd>⇧</kbd><kbd>F</kbd></div></div>
<div class="ks-item"><span class="ks-desc">Next result</span><div class="ks-keys"><kbd>F3</kbd></div></div>
<div class="ks-item"><span class="ks-desc">Previous result</span><div class="ks-keys"><kbd>⇧</kbd><kbd>F3</kbd></div></div>
</div>
</div>
<div class="ks-group" data-group="view">
<h2 class="ks-group-title">View</h2>
<div class="ks-list">
<div class="ks-item"><span class="ks-desc">Toggle sidebar</span><div class="ks-keys"><kbd>⌘</kbd><kbd>B</kbd></div></div>
<div class="ks-item"><span class="ks-desc">Toggle terminal</span><div class="ks-keys"><kbd>⌃</kbd><kbd>`</kbd></div></div>
<div class="ks-item"><span class="ks-desc">Zoom in</span><div class="ks-keys"><kbd>⌘</kbd><kbd>+</kbd></div></div>
<div class="ks-item"><span class="ks-desc">Zoom out</span><div class="ks-keys"><kbd>⌘</kbd><kbd>-</kbd></div></div>
<div class="ks-item"><span class="ks-desc">Reset zoom</span><div class="ks-keys"><kbd>⌘</kbd><kbd>0</kbd></div></div>
</div>
</div>
<div class="ks-group" data-group="git">
<h2 class="ks-group-title">Git</h2>
<div class="ks-list">
<div class="ks-item"><span class="ks-desc">Open source control</span><div class="ks-keys"><kbd>⌃</kbd><kbd>⇧</kbd><kbd>G</kbd></div></div>
<div class="ks-item"><span class="ks-desc">Stage hunk</span><div class="ks-keys"><kbd>⌘</kbd><kbd>K</kbd><kbd>⌘</kbd><kbd>S</kbd></div></div>
<div class="ks-item"><span class="ks-desc">Commit</span><div class="ks-keys"><kbd>⌘</kbd><kbd>Enter</kbd></div></div>
</div>
</div>
</div>
<div class="ks-empty" id="ksEmpty" hidden>No shortcuts matching "<span id="ksEmptyTerm"></span>"</div>
</div>
<script src="script.js"></script>
</body>
</html>import { useState, useEffect } from "react";
interface Shortcut {
description: string;
keys: string[];
}
interface Group {
category: string;
shortcuts: Shortcut[];
}
const SHORTCUTS: Group[] = [
{
category: "Navigation",
shortcuts: [
{ description: "Command palette", keys: ["⌘", "K"] },
{ description: "Quick open file", keys: ["⌘", "P"] },
{ description: "Go to line", keys: ["⌃", "G"] },
{ description: "Go to symbol", keys: ["⌘", "⇧", "O"] },
{ description: "Toggle sidebar", keys: ["⌘", "B"] },
],
},
{
category: "Editing",
shortcuts: [
{ description: "Duplicate line", keys: ["⌘", "⇧", "D"] },
{ description: "Delete line", keys: ["⌘", "⇧", "K"] },
{ description: "Move line up", keys: ["⌥", "↑"] },
{ description: "Move line down", keys: ["⌥", "↓"] },
{ description: "Comment line", keys: ["⌘", "/"] },
{ description: "Format document", keys: ["⌥", "⇧", "F"] },
],
},
{
category: "Selection",
shortcuts: [
{ description: "Select word", keys: ["⌘", "D"] },
{ description: "Select line", keys: ["⌘", "L"] },
{ description: "Select all", keys: ["⌘", "A"] },
{ description: "Multi-cursor", keys: ["⌥", "Click"] },
{ description: "Expand selection", keys: ["⌃", "⇧", "→"] },
],
},
{
category: "Terminal",
shortcuts: [
{ description: "New terminal", keys: ["⌃", "`"] },
{ description: "Kill terminal", keys: ["⌃", "C"] },
{ description: "Clear", keys: ["⌃", "K"] },
{ description: "Previous command", keys: ["↑"] },
],
},
];
const KEY_MAP: Record<string, string> = {
Meta: "⌘",
Control: "⌃",
Alt: "⌥",
Shift: "⇧",
ArrowUp: "↑",
ArrowDown: "↓",
ArrowLeft: "←",
ArrowRight: "→",
Backquote: "`",
Slash: "/",
Enter: "↩",
Escape: "⎋",
Tab: "⇥",
Backspace: "⌫",
Delete: "⌦",
" ": "Space",
};
function normalizeKey(key: string, code: string): string {
if (KEY_MAP[key]) return KEY_MAP[key];
if (KEY_MAP[code]) return KEY_MAP[code];
if (key.length === 1) return key.toUpperCase();
return key;
}
export default function KeyboardShortcutRC() {
const [search, setSearch] = useState("");
const [pressed, setPressed] = useState<Set<string>>(new Set());
useEffect(() => {
let clearTimer: ReturnType<typeof setTimeout>;
const onKeyDown = (e: KeyboardEvent) => {
const label = normalizeKey(e.key, e.code);
setPressed((prev) => new Set([...prev, label]));
clearTimeout(clearTimer);
};
const onKeyUp = () => {
clearTimer = setTimeout(() => setPressed(new Set()), 1000);
};
window.addEventListener("keydown", onKeyDown);
window.addEventListener("keyup", onKeyUp);
return () => {
window.removeEventListener("keydown", onKeyDown);
window.removeEventListener("keyup", onKeyUp);
};
}, []);
const isActive = (keys: string[]) => keys.length > 0 && keys.every((k) => pressed.has(k));
const q = search.toLowerCase();
const filtered = SHORTCUTS.map((g) => ({
...g,
shortcuts: g.shortcuts.filter(
(s) =>
s.description.toLowerCase().includes(q) ||
s.keys.some((k) => k.toLowerCase().includes(q)) ||
g.category.toLowerCase().includes(q)
),
})).filter((g) => g.shortcuts.length > 0);
return (
<div className="min-h-screen bg-[#0d1117] p-6 flex justify-center">
<div className="w-full max-w-[680px] space-y-5">
{/* Header */}
<div className="space-y-3">
<div className="flex items-center justify-between">
<h2 className="text-[15px] font-bold text-[#e6edf3]">Keyboard Shortcuts</h2>
{pressed.size > 0 && (
<div className="flex items-center gap-1.5">
<span className="text-[11px] text-[#8b949e]">Detecting:</span>
{[...pressed].map((k) => (
<kbd
key={k}
className="px-1.5 py-0.5 bg-[#58a6ff]/20 border border-[#58a6ff]/50 rounded text-[11px] font-mono font-bold text-[#58a6ff]"
>
{k}
</kbd>
))}
</div>
)}
</div>
<input
type="text"
placeholder="Search shortcuts…"
value={search}
onChange={(e) => setSearch(e.target.value)}
className="w-full bg-[#21262d] border border-[#30363d] rounded-lg px-3 py-2 text-[13px] text-[#e6edf3] placeholder-[#484f58] focus:outline-none focus:border-[#58a6ff] transition-colors"
/>
<p className="text-[11px] text-[#484f58]">
Press any key combination — matching shortcuts will highlight.
</p>
</div>
{/* Groups */}
<div className="space-y-4">
{filtered.map((group) => (
<div
key={group.category}
className="bg-[#161b22] border border-[#30363d] rounded-xl overflow-hidden"
>
<div className="px-4 py-2.5 bg-[#21262d] border-b border-[#30363d]">
<span className="text-[11px] font-bold text-[#8b949e] uppercase tracking-wider">
{group.category}
</span>
</div>
<div className="divide-y divide-[#21262d]">
{group.shortcuts.map((s) => {
const active = isActive(s.keys);
return (
<div
key={s.description}
className={`flex items-center justify-between px-4 py-2.5 transition-colors ${
active ? "bg-[#58a6ff]/[0.08]" : "hover:bg-white/[0.02]"
}`}
>
<span
className={`text-[13px] transition-colors ${
active ? "text-[#e6edf3] font-semibold" : "text-[#8b949e]"
}`}
>
{s.description}
</span>
<div className="flex items-center gap-1">
{s.keys.map((k, i) => (
<kbd
key={i}
className={`px-2 py-0.5 rounded text-[12px] font-mono font-bold border transition-all ${
active && pressed.has(k)
? "bg-[#58a6ff]/20 border-[#58a6ff]/60 text-[#58a6ff] scale-110"
: "bg-[#21262d] border-[#30363d] text-[#e6edf3]"
}`}
>
{k}
</kbd>
))}
</div>
</div>
);
})}
</div>
</div>
))}
</div>
</div>
</div>
);
}<script setup>
import { ref, computed, onMounted, onUnmounted } from "vue";
const SHORTCUTS = [
{
category: "Navigation",
shortcuts: [
{ description: "Command palette", keys: ["\u2318", "K"] },
{ description: "Quick open file", keys: ["\u2318", "P"] },
{ description: "Go to line", keys: ["\u2303", "G"] },
{ description: "Go to symbol", keys: ["\u2318", "\u21E7", "O"] },
{ description: "Toggle sidebar", keys: ["\u2318", "B"] },
],
},
{
category: "Editing",
shortcuts: [
{ description: "Duplicate line", keys: ["\u2318", "\u21E7", "D"] },
{ description: "Delete line", keys: ["\u2318", "\u21E7", "K"] },
{ description: "Move line up", keys: ["\u2325", "\u2191"] },
{ description: "Move line down", keys: ["\u2325", "\u2193"] },
{ description: "Comment line", keys: ["\u2318", "/"] },
{ description: "Format document", keys: ["\u2325", "\u21E7", "F"] },
],
},
{
category: "Selection",
shortcuts: [
{ description: "Select word", keys: ["\u2318", "D"] },
{ description: "Select line", keys: ["\u2318", "L"] },
{ description: "Select all", keys: ["\u2318", "A"] },
{ description: "Multi-cursor", keys: ["\u2325", "Click"] },
{ description: "Expand selection", keys: ["\u2303", "\u21E7", "\u2192"] },
],
},
{
category: "Terminal",
shortcuts: [
{ description: "New terminal", keys: ["\u2303", "`"] },
{ description: "Kill terminal", keys: ["\u2303", "C"] },
{ description: "Clear", keys: ["\u2303", "K"] },
{ description: "Previous command", keys: ["\u2191"] },
],
},
];
const KEY_MAP = {
Meta: "\u2318",
Control: "\u2303",
Alt: "\u2325",
Shift: "\u21E7",
ArrowUp: "\u2191",
ArrowDown: "\u2193",
ArrowLeft: "\u2190",
ArrowRight: "\u2192",
Backquote: "`",
Slash: "/",
Enter: "\u21A9",
Escape: "\u238B",
Tab: "\u21E5",
Backspace: "\u232B",
Delete: "\u2326",
" ": "Space",
};
function normalizeKey(key, code) {
if (KEY_MAP[key]) return KEY_MAP[key];
if (KEY_MAP[code]) return KEY_MAP[code];
if (key.length === 1) return key.toUpperCase();
return key;
}
const search = ref("");
const pressed = ref(new Set());
let clearTimer = null;
function onKeyDown(e) {
const label = normalizeKey(e.key, e.code);
pressed.value = new Set([...pressed.value, label]);
clearTimeout(clearTimer);
}
function onKeyUp() {
clearTimer = setTimeout(() => {
pressed.value = new Set();
}, 1000);
}
onMounted(() => {
window.addEventListener("keydown", onKeyDown);
window.addEventListener("keyup", onKeyUp);
});
onUnmounted(() => {
window.removeEventListener("keydown", onKeyDown);
window.removeEventListener("keyup", onKeyUp);
});
function isActive(keys) {
return keys.length > 0 && keys.every((k) => pressed.value.has(k));
}
const filtered = computed(() => {
const q = search.value.toLowerCase();
return SHORTCUTS.map((g) => ({
...g,
shortcuts: g.shortcuts.filter(
(s) =>
s.description.toLowerCase().includes(q) ||
s.keys.some((k) => k.toLowerCase().includes(q)) ||
g.category.toLowerCase().includes(q)
),
})).filter((g) => g.shortcuts.length > 0);
});
const pressedKeys = computed(() => [...pressed.value]);
</script>
<template>
<div style="min-height:100vh;background:#0d1117;padding:1.5rem;display:flex;justify-content:center;font-family:system-ui,-apple-system,sans-serif">
<div style="width:100%;max-width:680px;display:flex;flex-direction:column;gap:1.25rem">
<!-- Header -->
<div style="display:flex;flex-direction:column;gap:0.75rem">
<div style="display:flex;align-items:center;justify-content:space-between">
<h2 style="font-size:15px;font-weight:700;color:#e6edf3;margin:0">Keyboard Shortcuts</h2>
<div v-if="pressedKeys.length > 0" style="display:flex;align-items:center;gap:6px">
<span style="font-size:11px;color:#8b949e">Detecting:</span>
<kbd
v-for="k in pressedKeys"
:key="k"
style="padding:2px 6px;background:rgba(88,166,255,0.2);border:1px solid rgba(88,166,255,0.5);border-radius:4px;font-size:11px;font-family:monospace;font-weight:700;color:#58a6ff"
>{{ k }}</kbd>
</div>
</div>
<input
type="text"
placeholder="Search shortcuts..."
v-model="search"
style="width:100%;background:#21262d;border:1px solid #30363d;border-radius:0.5rem;padding:0.5rem 0.75rem;font-size:13px;color:#e6edf3;outline:none;box-sizing:border-box"
/>
<p style="font-size:11px;color:#484f58;margin:0">Press any key combination — matching shortcuts will highlight.</p>
</div>
<!-- Groups -->
<div style="display:flex;flex-direction:column;gap:1rem">
<div v-for="group in filtered" :key="group.category" style="background:#161b22;border:1px solid #30363d;border-radius:0.75rem;overflow:hidden">
<div style="padding:0.625rem 1rem;background:#21262d;border-bottom:1px solid #30363d">
<span style="font-size:11px;font-weight:700;color:#8b949e;text-transform:uppercase;letter-spacing:0.08em">{{ group.category }}</span>
</div>
<div>
<div
v-for="s in group.shortcuts"
:key="s.description"
:style="{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
padding: '0.625rem 1rem',
borderTop: '1px solid #21262d',
background: isActive(s.keys) ? 'rgba(88,166,255,0.08)' : 'transparent',
}"
>
<span :style="{ fontSize: '13px', color: isActive(s.keys) ? '#e6edf3' : '#8b949e', fontWeight: isActive(s.keys) ? '600' : '400' }">{{ s.description }}</span>
<div style="display:flex;align-items:center;gap:4px">
<kbd
v-for="(k, i) in s.keys"
:key="i"
:style="{
padding: '2px 8px',
borderRadius: '4px',
fontSize: '12px',
fontFamily: 'monospace',
fontWeight: '700',
border: isActive(s.keys) && pressed.has(k) ? '1px solid rgba(88,166,255,0.6)' : '1px solid #30363d',
background: isActive(s.keys) && pressed.has(k) ? 'rgba(88,166,255,0.2)' : '#21262d',
color: isActive(s.keys) && pressed.has(k) ? '#58a6ff' : '#e6edf3',
transform: isActive(s.keys) && pressed.has(k) ? 'scale(1.1)' : 'scale(1)',
transition: 'all 0.15s',
}"
>{{ k }}</kbd>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template><script>
import { onMount, onDestroy } from "svelte";
const SHORTCUTS = [
{
category: "Navigation",
shortcuts: [
{ description: "Command palette", keys: ["\u2318", "K"] },
{ description: "Quick open file", keys: ["\u2318", "P"] },
{ description: "Go to line", keys: ["\u2303", "G"] },
{ description: "Go to symbol", keys: ["\u2318", "\u21E7", "O"] },
{ description: "Toggle sidebar", keys: ["\u2318", "B"] },
],
},
{
category: "Editing",
shortcuts: [
{ description: "Duplicate line", keys: ["\u2318", "\u21E7", "D"] },
{ description: "Delete line", keys: ["\u2318", "\u21E7", "K"] },
{ description: "Move line up", keys: ["\u2325", "\u2191"] },
{ description: "Move line down", keys: ["\u2325", "\u2193"] },
{ description: "Comment line", keys: ["\u2318", "/"] },
{ description: "Format document", keys: ["\u2325", "\u21E7", "F"] },
],
},
{
category: "Selection",
shortcuts: [
{ description: "Select word", keys: ["\u2318", "D"] },
{ description: "Select line", keys: ["\u2318", "L"] },
{ description: "Select all", keys: ["\u2318", "A"] },
{ description: "Multi-cursor", keys: ["\u2325", "Click"] },
{ description: "Expand selection", keys: ["\u2303", "\u21E7", "\u2192"] },
],
},
{
category: "Terminal",
shortcuts: [
{ description: "New terminal", keys: ["\u2303", "`"] },
{ description: "Kill terminal", keys: ["\u2303", "C"] },
{ description: "Clear", keys: ["\u2303", "K"] },
{ description: "Previous command", keys: ["\u2191"] },
],
},
];
const KEY_MAP = {
Meta: "\u2318",
Control: "\u2303",
Alt: "\u2325",
Shift: "\u21E7",
ArrowUp: "\u2191",
ArrowDown: "\u2193",
ArrowLeft: "\u2190",
ArrowRight: "\u2192",
Backquote: "`",
Slash: "/",
Enter: "\u21A9",
Escape: "\u238B",
Tab: "\u21E5",
Backspace: "\u232B",
Delete: "\u2326",
" ": "Space",
};
function normalizeKey(key, code) {
if (KEY_MAP[key]) return KEY_MAP[key];
if (KEY_MAP[code]) return KEY_MAP[code];
if (key.length === 1) return key.toUpperCase();
return key;
}
let search = "";
let pressed = new Set();
let clearTimer = null;
function onKeyDown(e) {
const label = normalizeKey(e.key, e.code);
pressed = new Set([...pressed, label]);
clearTimeout(clearTimer);
}
function onKeyUp() {
clearTimer = setTimeout(() => {
pressed = new Set();
}, 1000);
}
onMount(() => {
window.addEventListener("keydown", onKeyDown);
window.addEventListener("keyup", onKeyUp);
});
onDestroy(() => {
if (typeof window !== "undefined") {
window.removeEventListener("keydown", onKeyDown);
window.removeEventListener("keyup", onKeyUp);
}
});
function isActive(keys) {
return keys.length > 0 && keys.every((k) => pressed.has(k));
}
$: pressedKeys = [...pressed];
$: filtered = (() => {
const q = search.toLowerCase();
return SHORTCUTS.map((g) => ({
...g,
shortcuts: g.shortcuts.filter(
(s) =>
s.description.toLowerCase().includes(q) ||
s.keys.some((k) => k.toLowerCase().includes(q)) ||
g.category.toLowerCase().includes(q)
),
})).filter((g) => g.shortcuts.length > 0);
})();
</script>
<div style="min-height:100vh;background:#0d1117;padding:1.5rem;display:flex;justify-content:center;font-family:system-ui,-apple-system,sans-serif">
<div style="width:100%;max-width:680px;display:flex;flex-direction:column;gap:1.25rem">
<!-- Header -->
<div style="display:flex;flex-direction:column;gap:0.75rem">
<div style="display:flex;align-items:center;justify-content:space-between">
<h2 style="font-size:15px;font-weight:700;color:#e6edf3;margin:0">Keyboard Shortcuts</h2>
{#if pressedKeys.length > 0}
<div style="display:flex;align-items:center;gap:6px">
<span style="font-size:11px;color:#8b949e">Detecting:</span>
{#each pressedKeys as k}
<kbd style="padding:2px 6px;background:rgba(88,166,255,0.2);border:1px solid rgba(88,166,255,0.5);border-radius:4px;font-size:11px;font-family:monospace;font-weight:700;color:#58a6ff">{k}</kbd>
{/each}
</div>
{/if}
</div>
<input
type="text"
placeholder="Search shortcuts..."
bind:value={search}
style="width:100%;background:#21262d;border:1px solid #30363d;border-radius:0.5rem;padding:0.5rem 0.75rem;font-size:13px;color:#e6edf3;outline:none;box-sizing:border-box"
/>
<p style="font-size:11px;color:#484f58;margin:0">Press any key combination — matching shortcuts will highlight.</p>
</div>
<!-- Groups -->
<div style="display:flex;flex-direction:column;gap:1rem">
{#each filtered as group}
<div style="background:#161b22;border:1px solid #30363d;border-radius:0.75rem;overflow:hidden">
<div style="padding:0.625rem 1rem;background:#21262d;border-bottom:1px solid #30363d">
<span style="font-size:11px;font-weight:700;color:#8b949e;text-transform:uppercase;letter-spacing:0.08em">{group.category}</span>
</div>
<div>
{#each group.shortcuts as s}
<div style="display:flex;align-items:center;justify-content:space-between;padding:0.625rem 1rem;border-top:1px solid #21262d;background:{isActive(s.keys) ? 'rgba(88,166,255,0.08)' : 'transparent'}">
<span style="font-size:13px;color:{isActive(s.keys) ? '#e6edf3' : '#8b949e'};font-weight:{isActive(s.keys) ? '600' : '400'}">{s.description}</span>
<div style="display:flex;align-items:center;gap:4px">
{#each s.keys as k, i}
<kbd style="padding:2px 8px;border-radius:4px;font-size:12px;font-family:monospace;font-weight:700;border:1px solid {isActive(s.keys) && pressed.has(k) ? 'rgba(88,166,255,0.6)' : '#30363d'};background:{isActive(s.keys) && pressed.has(k) ? 'rgba(88,166,255,0.2)' : '#21262d'};color:{isActive(s.keys) && pressed.has(k) ? '#58a6ff' : '#e6edf3'};transform:{isActive(s.keys) && pressed.has(k) ? 'scale(1.1)' : 'scale(1)'};transition:all 0.15s">{k}</kbd>
{/each}
</div>
</div>
{/each}
</div>
</div>
{/each}
</div>
</div>
</div>Keyboard shortcut reference sheet organized by category (Navigation, Editing, Selection, etc.) with styled KBD keys, modifier symbols (⌘ ⇧ ⌥ ⌃), and a live search filter. CSS-first, minimal JS.