VibeWeek
Home/Grow/Keyboard Shortcuts & Command Palette: Power Users Convert at 5x When You Add Them

Keyboard Shortcuts & Command Palette: Power Users Convert at 5x When You Add Them

⬅️ Day 6: Grow Overview

If your SaaS in 2026 has 10+ minutes/day average use per active user, keyboard shortcuts and a Cmd+K command palette aren't optional features — they're the difference between "useful tool" and "tool that fits my workflow." Power users (5-15% of your DAU; 50%+ of revenue) DO use shortcuts; they expect them. Consumers won't notice; teams that use your product all day will. Most indie SaaS skips shortcuts (assumed: "not worth it for our scale"); then watches power users churn to competitors who shipped them. The fix is a deliberate keyboard-first layer: global shortcuts (Cmd+K, Cmd+S, Esc), per-page shortcuts (j/k navigation, ?), command palette as the discoverability surface.

A working keyboard-shortcut implementation answers: which shortcuts to ship (the universal 8 + per-product), how to expose discoverability (? = help; tooltips; cheatsheet), how to handle conflicts (browser vs app), how to handle accessibility (don't break screen readers), how to make custom (let users remap), how to ship Cmd+K palette with fuzzy-match, and how to test cross-browser + cross-OS.

This guide is the implementation playbook for keyboard UX. Companion to Search Autocomplete & Typeahead, Real-time Collaboration, Internal Admin Tools, and Performance Optimization.

Why Keyboard Shortcuts Matter

Get the value model clear first.

Help me understand the value.

The data:

**Power user behavior**:
- Power users (top 10-20% of DAU) drive 50-80% of revenue and retention
- They use products that fit their workflow
- Workflow = speed = keyboard

**The conversion math**:
- App with shortcuts: power users complete tasks 2-5x faster
- App without: same task; lots of mouse + clicking
- Compounded over thousands of daily uses → power users notice

**The category leaders' pattern**:

Linear: Cmd+K is THE feature; entire workflow keyboard-first
Notion: 30+ shortcuts; / commands inline
Slack: full keyboard navigation; channels + threads via shortcuts
Figma: keyboard-driven design tools
GitHub: ?-shortcut for help; / for search; gp for pull-requests
Gmail / Superhuman: keyboard-only email triage

These are the companies people switch TO. Their UX investment in keyboard pays.

**The indie SaaS opportunity**:

Most indie SaaS doesn't have shortcuts.
Adding them = competitive advantage.
Cost: 2-4 weeks of frontend work.
Result: power-user retention up; word-of-mouth from users who LOVE shortcuts.

For my product:
- Power-user % of DAU
- Average session length
- Compete with shortcut-rich tools?

Output:
1. Investment justification
2. Power-user impact estimate
3. Priority

The mistake most indie SaaS make: "we don't have power users yet." You DO; they're the 5% who use you 5+ hours/day. Surveying them: "what would make this faster?" Answer is always: keyboard. Ship it.

The Universal 8 Shortcuts

Help me ship the basics.

Every modern web SaaS in 2026 should support these 8 shortcuts:

**1. Cmd/Ctrl+K** — Open command palette / search
Universal across modern apps. Users expect it.

**2. Esc** — Close modal / clear selection / dismiss
Standard exit; should always work.

**3. /** — Focus search input
GitHub / Twitter / Discord convention.

**4. ?** — Show keyboard shortcut help
Universal "show me what I can do" key.

**5. Cmd/Ctrl+S** — Save (when applicable)
Don't fight the browser; users press this; intercept gracefully.

**6. Cmd/Ctrl+Z / Shift+Cmd+Z** — Undo / redo
Wherever editable state exists.

**7. Tab / Shift+Tab** — Navigate focusable elements
Built-in but ensure your custom components participate.

**8. Enter** — Confirm / submit primary action
On focused buttons / form submits.

**Implementation considerations**:

**Modifier keys**:
- macOS: Cmd (⌘)
- Windows / Linux: Ctrl
- Detection: `navigator.platform` or check both
- Display: show "⌘K" on Mac; "Ctrl+K" on Windows

```typescript
const isMac = navigator.platform.toUpperCase().includes('MAC');
const cmdLabel = isMac ? '⌘' : 'Ctrl';

useHotkeys('mod+k', () => openCommandPalette()); // 'mod' = Cmd on Mac, Ctrl elsewhere

Browser collisions:

  • Cmd+S: browser tries to save page → preventDefault
  • Cmd+W: closes tab → DON'T intercept (browser-level)
  • Cmd+T: new tab → don't intercept
  • Cmd+L: focus URL bar → don't intercept

Rule: only intercept what users expect your app to handle.

Form / input safety:

  • Single-key shortcuts (?, /, j/k) should NOT fire when user is typing in input
  • Check event.target is not input/textarea/contenteditable
function isTypingInInput() {
  const tag = document.activeElement?.tagName;
  return tag === 'INPUT' || tag === 'TEXTAREA' || 
    document.activeElement?.getAttribute('contenteditable') === 'true';
}

// Listener
document.addEventListener('keydown', (e) => {
  if (isTypingInInput()) return; // Skip
  if (e.key === '?') showHelp();
});

For my product:

  • Universal 8 audit
  • Conflicts to handle

Output:

  1. Universal 8 implementation
  2. Per-OS handling
  3. Input-safety

The discipline: **always show shortcut hints in UI**. Tooltip on the menu item: "Save (⌘S)." Users see; learn; use. Hidden shortcuts = unused.

## Cmd+K Command Palette: The Anchor Feature

Help me build a command palette.

The Cmd+K command palette is a single keyboard shortcut that opens a fuzzy-search modal listing all actions in the app.

Examples done well:

  • Linear: Cmd+K opens; types anything; finds issues, projects, settings, actions
  • Slack: Cmd+K = quick switcher (channels + DMs)
  • Notion: Cmd+K = search + actions
  • GitHub: Cmd+K (recent addition) = search + commands

The structure:

[Cmd+K opens]
  ↓
[Modal with input + list]
  - User types
  - Fuzzy-match across:
    * Pages (Dashboard, Settings, Profile, ...)
    * Actions (Create new, Invite user, Export data, ...)
    * Recent (last viewed items)
    * Items in your data (issues / docs / customers)
  - Arrow keys navigate
  - Enter executes
  - Esc closes

Implementation: cmdk-react (current 2026 default):

import { Command } from 'cmdk';

function CommandPalette({ open, onClose }) {
  const router = useRouter();
  const [search, setSearch] = useState('');
  
  return (
    <Command.Dialog open={open} onOpenChange={onClose}>
      <Command.Input value={search} onValueChange={setSearch} placeholder="Type a command or search..." />
      
      <Command.List>
        <Command.Empty>No results found.</Command.Empty>
        
        <Command.Group heading="Pages">
          <Command.Item onSelect={() => router.push('/')}>
            Home
            <Command.Shortcut>⌘H</Command.Shortcut>
          </Command.Item>
          <Command.Item onSelect={() => router.push('/settings')}>
            Settings
            <Command.Shortcut>⌘,</Command.Shortcut>
          </Command.Item>
        </Command.Group>
        
        <Command.Group heading="Actions">
          <Command.Item onSelect={() => createNewDoc()}>
            Create new doc
            <Command.Shortcut>⌘N</Command.Shortcut>
          </Command.Item>
        </Command.Group>
        
        <Command.Group heading="Recent">
          {recentItems.map(item => (
            <Command.Item key={item.id} onSelect={() => router.push(`/items/${item.id}`)}>
              {item.title}
            </Command.Item>
          ))}
        </Command.Group>
      </Command.List>
    </Command.Dialog>
  );
}

// Hook to open
function useCommandPalette() {
  const [open, setOpen] = useState(false);
  
  useHotkeys('mod+k', () => setOpen(o => !o));
  
  return { open, setOpen };
}

Design choices:

  • Fuzzy match (cmdk handles via Fuse-like algorithm)
  • Group categories (Pages / Actions / Recent / Items)
  • Show shortcuts inline (⌘N hints)
  • Empty state with help message
  • Loading state for async items

Async data:

For fetching items:

const [items, setItems] = useState([]);
const debouncedSearch = useDebouncedValue(search, 100);

useEffect(() => {
  if (!debouncedSearch) return;
  fetch(`/api/search?q=${debouncedSearch}`).then(r => r.json()).then(setItems);
}, [debouncedSearch]);

For my product:

  • Top categories
  • Async data sources

Output:

  1. Command palette structure
  2. Implementation
  3. Categories

The single most-impactful UX feature you can ship in 2026: **Cmd+K palette**. Users who try it never go back. Worth the 1-2 weeks of work.

## Library Choices

Help me pick libraries.

The 2026 landscape:

Hotkey libraries:

  • react-hotkeys-hook — most-popular React hook
  • mousetrap — vanilla JS; battle-tested
  • tinykeys — modern; tiny; tree-shakable
  • Hotkeys.js — vanilla JS

Command palette:

  • cmdk (by pacocoursey) — 2026 standard React command palette
  • Headless UI Combobox — flexible primitive
  • Radix UI — primitives
  • Mantine Spotlight — if Mantine ecosystem

Recommendation:

For React in 2026:

  • cmdk for the command palette (proven; used by Vercel, Linear, etc.)
  • react-hotkeys-hook for global shortcuts
npm install cmdk react-hotkeys-hook

Key features cmdk gives you:

  • Fuzzy matching out of the box
  • Keyboard navigation built in
  • Accessible (ARIA correct)
  • Composable (groups, shortcuts, custom items)
  • Used by major apps

For my stack: [pick]

Output:

  1. Library pick
  2. Setup
  3. Migration if existing

The 2026 default: **cmdk + react-hotkeys-hook**. Combined: ~30KB; covers 90% of needs; ships in days.

## Discoverability: ? Key for Help

Help me make shortcuts discoverable.

The problem: shortcuts only help users who know they exist.

Solutions:

1. The ? key shortcut (universal convention)

User presses ? → modal showing all shortcuts.

useHotkeys('shift+/', (e) => {
  e.preventDefault();
  setShortcutsOpen(true);
});

function ShortcutsModal({ open }) {
  return (
    <Modal open={open}>
      <h2>Keyboard Shortcuts</h2>
      <table>
        <tr><td><kbd>⌘K</kbd></td><td>Open command palette</td></tr>
        <tr><td><kbd>⌘N</kbd></td><td>New document</td></tr>
        <tr><td><kbd>?</kbd></td><td>This help</td></tr>
        ...
      </table>
    </Modal>
  );
}

GitHub uses this; Gmail uses this; standard convention.

2. Tooltips on menu items showing shortcuts

Right-click menu / dropdown items show shortcut hint:

<DropdownItem onSelect={save}>
  Save document <span className="shortcut">⌘S</span>
</DropdownItem>

Users see; learn over time.

3. First-use tooltip popup

When user does an action mouse-only that has a shortcut, briefly show: "Did you know? You can also press ⌘N for this."

Show 2-3 times; respect dismissal.

4. Onboarding callout

In product tour: "Pro tip: press ⌘K anywhere to find anything."

5. Footer / status bar hint

Permanent small hint: "⌘K to search anywhere"

For my product: [discoverability today]

Output:

  1. Discovery surfaces
  2. ?-shortcut + modal
  3. Tooltip strategy

The single most-effective discovery tactic: **status-bar hint "⌘K to search anywhere"**. Persistent; subtle; eventually noticed by everyone. Costs nothing.

## Per-Product Shortcuts: The Tier Below Universal

Help me design custom shortcuts.

Beyond the universal 8, your product gets specific shortcuts.

Common patterns by product type:

Email-style apps (Gmail, Superhuman, Front):

  • j / k — next / previous message
  • r — reply
  • a — reply all
  • f — forward
  • e — archive
  • # — delete
  • s — star
  • c — compose new
  • Cmd+Enter — send

List / table-based apps (Linear, Notion DBs, Airtable):

  • j / k or / — navigate items
  • Enter — open item
  • n — new item
  • e — edit
  • Cmd+Enter — save and close
  • / — filter / search

Document editors (Notion, Google Docs, Linear):

  • Cmd+B — bold
  • Cmd+I — italic
  • Cmd+U — underline (or strikethrough)
  • Cmd+K — link
  • Tab / Shift+Tab — indent / outdent
  • Cmd+Shift+1-6 — heading levels

Code editors (VS Code, GitHub):

  • Different conventions; usually CTRL+SHIFT-prefix combos

Two-letter "vim-style" shortcuts (Linear, GitHub):

  • g d — go to dashboard
  • g s — go to settings
  • g i — go to inbox

These reduce conflicts; allow lots of shortcuts; require teaching.

Implementation pattern:

// Single-key (caution: only outside inputs)
useHotkeys('j', () => navigateNext());
useHotkeys('k', () => navigatePrev());

// Multi-key sequences (cmdk supports; or custom)
const [seq, setSeq] = useState('');
useEffect(() => {
  function handler(e) {
    if (isTypingInInput()) return;
    setSeq(s => s + e.key);
    setTimeout(() => setSeq(''), 1000); // Reset after 1s
  }
  document.addEventListener('keydown', handler);
  return () => document.removeEventListener('keydown', handler);
}, []);

useEffect(() => {
  if (seq === 'gd') router.push('/dashboard');
  if (seq === 'gs') router.push('/settings');
}, [seq]);

For my product:

  • Top 10 actions
  • Frequency of each

Output:

  1. Per-action shortcut
  2. Mnemonic strategy
  3. Conflict avoidance

The discipline: **make shortcuts mnemonic**. `n` for new; `e` for edit; `s` for save. Random shortcuts (Cmd+Q for "create issue") get forgotten. Predictable shortcuts get learned in a day.

## Accessibility: Don't Break Keyboard Users

Help me handle a11y.

The principle: shortcuts MUST coexist with default keyboard navigation, not replace it.

Required behaviors:

1. Tab still works Custom shortcuts shouldn't break tab focus order. Test: tab through your app; can keyboard-only users reach every interactive element?

2. Focus rings visible When user tabs / arrow-keys to a button: visible focus ring. Don't outline: none.

*:focus-visible {
  outline: 2px solid #4285f4;
  outline-offset: 2px;
}

3. Skip-to-content link

Hidden until focused; lets keyboard users skip nav:

<a href="#main" className="sr-only focus:not-sr-only">Skip to content</a>

4. Modifier-prefix shortcuts for global keys when typing

If n = "new item", what happens when user types n in a textarea? Solution: require modifier (Cmd+N) OR check input focus first.

5. ARIA-live announcements for shortcut-driven actions

User presses a to archive → announce "Archived" via live region:

<div role="status" aria-live="polite">{lastAction}</div>

Screen reader users hear feedback even though they didn't see UI change.

6. Don't override system shortcuts

  • Cmd+W (close tab)
  • Cmd+T (new tab)
  • Cmd+L (URL bar focus)
  • Cmd+Q (quit)

Browser-level; can't override on most browsers anyway. Don't try.

7. Shortcut help respects screen readers

The ? help modal should be readable. Don't use only visual <kbd> tags; include aria-label if confusing.

For my product: [a11y audit]

Output:

  1. Tab navigation test
  2. Focus ring discipline
  3. Skip link
  4. ARIA announcements

The discipline: **test keyboard-only**. Unplug your mouse for 30 minutes. Use your app. What's frustrating? Fix that. Most accessibility issues surface immediately with this exercise.

## Custom / Remappable Shortcuts (Optional)

Help me decide on remapping.

Should users customize shortcuts?

Pro-remapping:

  • Different muscle memory across apps
  • Disability accommodations
  • Vim users want vim mode
  • Power user preference

Anti-remapping:

  • Complexity to ship
  • Documentation gets confused
  • Most users don't customize
  • Edge-case bugs

The 2026 recommendation:

  • Don't ship in v1
  • Add when 1+ paying customer specifically asks
  • Implement via settings page; persist to user profile

When you do:

// User settings
const userShortcuts = {
  'open_palette': 'mod+k',
  'new_item': 'mod+n',
  'save': 'mod+s',
};

// Apply
Object.entries(userShortcuts).forEach(([action, keys]) => {
  useHotkeys(keys, () => actions[action]());
});

// Settings UI
<ShortcutSetting 
  action="new_item" 
  defaultKeys="mod+n"
  onChange={updateShortcut} 
/>

Vim mode (rare but valued):

For text editors / dev tools, vim mode is sometimes a feature. Library: codemirror-vim or @replit/vim Most users don't want; the few who do are vocal.

For my product: [scope]

Output:

  1. Remapping decision
  2. v1 vs later
  3. Implementation if shipping

The discipline: **don't gold-plate v1**. Universal 8 + Cmd+K + 5-10 product-specific shortcuts is enough. Remappability is v3 territory.

## Testing Keyboard UX

Help me test.

The tests:

1. Manual: keyboard-only session

Unplug mouse. Use app for 15-30 min. Note frustration points.

2. Cross-browser

Chrome, Firefox, Safari, Edge. Some shortcuts behave differently.

3. Cross-OS

macOS, Windows, Linux. Cmd vs Ctrl detection works?

4. Form / input behavior

Type in input fields; ensure single-key shortcuts don't fire.

5. Modal / overlay behavior

When modal open, do shortcuts still work? Should they? Esc closes modal? Ctrl+Z works inside vs outside?

6. Focus management

After action triggers, where does focus go? After clicking item via Cmd+K, focus should move to that item.

7. Screen reader test

VoiceOver / NVDA: do announcements work? Does keyboard nav reach everything?

8. Performance

Many global hotkey listeners can hurt performance. Profile: register lazy; unregister on unmount.

For my product: [tests today]

Output:

  1. Manual checklist
  2. CI / playwright tests
  3. A11y audit

The single most-useful test: **30 minutes mouse-free**. Reveals missing shortcuts; broken flows; rough edges. Better than any automated test for actual user experience.

## Common Keyboard Mistakes

Help me avoid mistakes.

The 10 mistakes:

1. Shortcuts fire while typing in inputs User types "n" in textarea; "new item" modal opens; data lost.

2. No discoverability Shortcuts exist but only insiders know.

3. Random / non-mnemonic Cmd+Q for "create issue" — confusing.

4. Browser-shortcut conflicts Override Cmd+W; users lose work when tab closes anyway.

5. No focus-visible styles Keyboard users can't see what's focused.

6. No skip-to-content link Keyboard users tab through 50 nav items first.

7. Cmd+K palette is slow Async data without "loading" state; feels broken.

8. Inconsistent shortcuts within product Different pages bind same key to different actions.

9. Mac/Windows label confusion Shows "Ctrl+K" on Mac; "⌘K" on Windows.

10. No screen-reader announcements Visually-impaired users can't tell action happened.

For my product: [risks]

Output:

  1. Top 3 risks
  2. Mitigations
  3. Audit checklist

The single most-painful mistake: **single-key shortcut firing while user types**. Power user types blog post in textarea; presses `n`; modal opens; loses focus + work. Always check input focus.

## What Done Looks Like

A working keyboard UX:
- Universal 8 shortcuts: Cmd+K, Esc, /, ?, Cmd+S, Cmd+Z, Tab, Enter
- Cmd+K command palette via cmdk; fuzzy match; categories; async data
- ? key opens shortcuts help modal
- Tooltips show shortcut hints on menu items
- Status-bar hint persistent
- Single-key shortcuts respect input focus
- Cross-OS (Cmd vs Ctrl) detection + display
- Screen-reader announcements for shortcut-driven actions
- Focus-visible styles preserved
- Skip-to-content link
- 30-minute mouse-free test passes

The proof you got it right: a power user adopts your app in week 1 because Cmd+K Just Works; learns 5 shortcuts in a week without training; never goes back to mouse-only competitors.

## See Also

- [Search Autocomplete & Typeahead](search-autocomplete-typeahead-chat.md) — Cmd+K palette uses these patterns
- [Real-time Collaboration](real-time-collaboration-chat.md) — collaborative shortcuts
- [Internal Admin Tools](internal-admin-tools-chat.md) — admin command palettes
- [Performance Optimization](performance-optimization-chat.md) — keyboard handlers add events; profile
- [Form Validation UX](form-validation-ux-chat.md) — Enter to submit
- [Onboarding Tour Implementation](onboarding-tour-implementation-chat.md) — surface shortcuts in onboarding
- [VibeReference: Accessibility](https://vibereference.dev/product-and-design/accessibility) — broader a11y context
- [VibeReference: React](https://vibereference.dev/frontend/react) — React patterns
- [VibeReference: Shadcn](https://vibereference.dev/frontend/shadcn) — Shadcn ships with cmdk integration