# Keyboard Shortcuts — Production Best Practices

Critical patterns learned from production use. For implementation steps, also read `impact-nova://command-palette`.

## Scope hierarchy (priority system)

```typescript
// Scope priority: higher numbers beat lower numbers
const SCOPE_PRIORITY = {
  global: 0,    // Always active, lowest priority
  module: 1,    // Module-level (e.g., Approval Hub)
  page: 2,      // Page-level (e.g., Dashboard, Planning)
  modal: 3,     // Modal/dialog overlay (highest priority)
};
```

**Key rule:** Page scope shortcuts override global scope shortcuts.

## Browser-reserved shortcuts (never use)

| Shortcut | Browser function | Alternative |
|----------|------------------|-------------|
| `Ctrl+Tab` | Switch browser tabs | `Option+ArrowRight` |
| `Cmd+T` | New browser tab | `Option+T` |
| `Cmd+W` | Close browser tab | `Option+W` |
| `Cmd+N` | New window | `Option+N` |
| `Cmd+Q` | Quit app | `Option+Q` |
| `Cmd+R` | Refresh page | `Option+R` |

## Safe shortcut patterns

### Tab navigation

- **Next tab:** `Option+ArrowRight` (⌥→)
- **Previous tab:** `Option+ArrowLeft` (⌥←)
- **First tab:** `Option+1` (⌥1)
- **Last tab:** `Option+9` (⌥9)

### Common application shortcuts

- **Command palette:** `Cmd+K` (⌘K)
- **Save:** `Cmd+S` (⌘S)
- **Copy:** `Cmd+C` (⌘C)
- **Paste:** `Cmd+V` (⌘V)
- **Undo:** `Cmd+Z` (⌘Z)
- **Redo:** `Cmd+Shift+Z` (⌘⇧Z)

## State synchronization (critical)

### Problem: duplicate state instances

```tsx
// Wrong — two separate state instances
function Page() {
  const { activeTab, setActiveTab } = useDashboard();
  useShortcuts({ activeTab, setActiveTab }); // State A

  return <Dashboard />; // Component creates State B internally
}
```

### Solution: single state source

```tsx
// Correct — single state instance
function Page() {
  const { activeTab, setActiveTab, ...allState } = useDashboard();
  useShortcuts({ activeTab, setActiveTab });

  return (
    <Dashboard
      activeTab={activeTab}
      setActiveTab={setActiveTab}
      {...allState}
    />
  );
}
```

## Defensive programming

```tsx
useShortcut({
  handler: () => {
    if (!tabs || tabs.length === 0) return;
    const currentIndex = tabs.findIndex((tab) => tab.id === activeTabId);
    const nextIndex = (currentIndex + 1) % tabs.length;
    setActiveTab(tabs[nextIndex].id);
  },
});
```

## Implementation checklist

- [ ] Identify browser conflicts for chosen shortcuts
- [ ] Verify scope hierarchy requirements
- [ ] Lift state to a common ancestor when shortcuts and UI must stay in sync
- [ ] Add defensive checks for empty/null data
- [ ] Test shortcuts in all target scopes
- [ ] Verify command palette shows correct shortcuts

## Common pitfalls

| Pitfall | Solution |
|---------|----------|
| `Ctrl+Tab` switches browser tabs | Use `Option+Arrow` for in-app tab navigation |
| Shortcuts update state but UI does not change | Lift state; pass props to child components |
| Runtime errors when tabs have not loaded | `if (!tabs?.length) return;` |
| Global shortcuts override page shortcuts | Use higher-priority scopes (`page` > `global`) |

## Additional resources

- `impact-nova://command-palette` — full implementation guide
- `impact-nova://best-practices` — general conventions
- `impact-nova://troubleshooting` — common issues and fixes
