Kiki

Keyboard Shortcuts

Component 13

About

A searchable keyboard-shortcuts cheat sheet. Press ? to pop a grouped, filterable list of every hotkey - written once as compact strings like 'mod+k' and rendered as platform-aware keycaps (Cmd on Mac, Ctrl elsewhere). Focus-trapped, Esc to close, reduced-motion aware, light and dark. Ships as <ShortcutsDialog> plus a useShortcuts() hook. React and framer-motion only, zero config.

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds Keyboard Shortcuts to your project and fits it to your theme.

Code

How Keyboard Shortcuts is used: the demo's code. The component's own source comes with a free account.

Usage.tsx

"use client";

import * as React from "react";
import { ShortcutsDialog, useShortcuts, type ShortcutGroup } from "@/components/ui/keyboard-shortcuts";

const GROUPS: ShortcutGroup[] = [
  {
    heading: "General",
    items: [
      { keys: "mod+k", label: "Open command menu" },
      { keys: "?", label: "Show keyboard shortcuts" },
      { keys: "mod+/", label: "Toggle comment" },
      { keys: "mod+,", label: "Open settings" },
    ],
  },
  {
    heading: "Navigation",
    items: [
      { keys: ["g h", "g d"], label: "Go home / dashboard" },
      { keys: "g i", label: "Go to inbox" },
      { keys: "mod+p", label: "Jump to file" },
      { keys: ["up", "down"], label: "Move between items" },
    ],
  },
  {
    heading: "Editing",
    items: [
      { keys: "mod+s", label: "Save" },
      { keys: "mod+z", label: "Undo" },
      { keys: "mod+shift+z", label: "Redo" },
      { keys: "mod+enter", label: "Submit" },
      { keys: "mod+backspace", label: "Delete line" },
    ],
  },
];

export default function KeyboardShortcutsDemo() {
  const [dark, setDark] = React.useState(false);
  const shortcuts = useShortcuts("?");

  React.useEffect(() => {
    const t = window.setTimeout(() => shortcuts.setOpen(true), 550);
    return () => window.clearTimeout(t);
  }, [shortcuts.setOpen]);

  return (
    <div className={dark ? "dark" : ""}>
      <div className="min-h-screen overflow-x-hidden bg-zinc-100 text-zinc-900 dark:bg-zinc-950 dark:text-zinc-100">
        <div className="mx-auto flex min-h-screen max-w-3xl flex-col p-4 sm:p-8">
          <header className="flex items-center justify-between">
            <div className="flex items-center gap-2.5">
              <div className="grid h-8 w-8 place-items-center rounded-[9px] border border-zinc-200/90 bg-gradient-to-b from-white to-zinc-100 text-[13px] font-semibold text-zinc-700 shadow-[0_1px_2px_rgba(0,0,0,0.05),inset_0_-1px_0_rgba(0,0,0,0.04)] dark:border-zinc-700 dark:from-zinc-800 dark:to-zinc-900 dark:text-zinc-200">
                ⌘
              </div>
              <div className="flex flex-col leading-tight">
                <span className="text-[13px] font-semibold tracking-tight">Keyflow</span>
                <span className="text-[11px] text-zinc-400">Untitled draft</span>
              </div>
            </div>

            <div className="flex items-center gap-2">
              <button
                onClick={shortcuts.toggle}
                className="group inline-flex items-center gap-2 rounded-xl border border-zinc-200 bg-white py-1.5 pl-3 pr-2 text-[12.5px] font-medium text-zinc-600 transition-colors hover:bg-zinc-50 dark:border-zinc-800 dark:bg-zinc-900 dark:text-zinc-300 dark:hover:bg-zinc-800/60"
              >
                Shortcuts
                <kbd className="grid h-[18px] min-w-[18px] place-items-center rounded-[5px] border border-zinc-200/90 bg-gradient-to-b from-white to-zinc-50 px-1 text-[11px] font-medium leading-none text-zinc-500 shadow-[0_1px_0_rgba(0,0,0,0.04)] dark:border-zinc-700 dark:from-zinc-800 dark:to-zinc-800/70 dark:text-zinc-300">
                  ?
                </kbd>
              </button>
              <button
                onClick={() => setDark((d) => !d)}
                aria-label="Toggle theme"
                className="h-9 w-9 shrink-0 rounded-full border border-zinc-200 text-zinc-500 transition-colors hover:bg-white dark:border-zinc-800 dark:hover:bg-zinc-900"
              >
                {dark ? "☀" : "☽"}
              </button>
            </div>
          </header>

          <div className="mt-6 flex-1 rounded-2xl border border-zinc-200 bg-white p-6 dark:border-zinc-800 dark:bg-zinc-900 sm:p-8">
            <h1 className="text-[20px] font-semibold tracking-tight">Untitled document</h1>
            <p className="mt-3 max-w-prose text-[13.5px] leading-relaxed text-zinc-500 dark:text-zinc-400">
              Every fast app has a keyboard layer. Press{" "}
              <kbd className="rounded border border-zinc-200 px-1.5 py-0.5 text-[11.5px] text-zinc-500 dark:border-zinc-700 dark:text-zinc-300">
                ?
              </kbd>{" "}
              to see the full map - search it, learn one, close it. This overlay is the
              whole thing: bring your groups, it renders the chips and handles the rest.
            </p>
            <div className="mt-6 space-y-2">
              {[92, 78, 85, 60].map((w, i) => (
                <div
                  key={i}
                  className="h-2.5 rounded-full bg-zinc-100 dark:bg-zinc-800"
                  style={{ width: `${w}%` }}
                />
              ))}
            </div>
          </div>
        </div>
      </div>

      <ShortcutsDialog
        groups={GROUPS}
        open={shortcuts.open}
        onOpenChange={shortcuts.setOpen}
      />
    </div>
  );
}

Dependencies

More by Kiki

View all
  • Filter Token Bar

    Filter Token Bar

    522
  • Compose

    Compose

    423
  • Product Tour

    Product Tour

    216
  • Tier List Maker

    Tier List Maker

    138
  • Draggable Photo Stack

    Draggable Photo Stack

    84
  • Morphing Scroll Navbar

    Morphing Scroll Navbar

    81
  • Selection Bubble Menu

    Selection Bubble Menu

    35
  • 3D Before & After Image Slider

    3D Before & After Image Slider

    32