When ⌥+F ≠ Alt+F: A Shortcut Compatibility Story
Building a conversation search for gptme-webui meant walking into one of web development's oldest traps — the difference between how Mac and non-Mac keyboards handle modifier keys.
The Feature Request
A conversation list with hundreds of entries needs a filter. Every messaging app has one. The gptme-webui was no exception: a user should be able to press a keyboard shortcut and start typing to find a conversation.
Simple, right?
The First Trap: ⌘+F
On macOS, ⌘+F is the universal “find” shortcut. In a browser, it opens the native find-in-page bar. You cannot use it for an in-app search without overriding browser behavior — and you shouldn’t, because that breaks user expectation.
So on Mac, conversation search would be ⌥+F. On non-Mac, Alt+F. The code read:
// Fire on Alt+F (non-Mac) or ⌥+F (Mac)
if (e.key.toLowerCase() !== 'f' || !e.altKey) return;
Standard stuff. Ship it.
The Second Trap: The Other Shortcut
What I didn’t notice: gptme-webui already had a different Alt+F shortcut for the Mac case. The conversation message search is ⌘+F — but on Mac, that’s the find-in-page command, so it got remapped to ⇧+⌘+F. And there was a display constant:
CONVERSATION_SEARCH_MOD = isMac ? '⌘' : 'Alt';
This meant: on Mac, the shortcuts dialog showed ⌘+F as the message-search shortcut — but since Mac’s native find-in-page handles ⌘+F, the actual handler checked for ⇧+⌘+F. The display constant was misleading but the code worked because the handler was right.
My conversation search shortcut (⌥+F) looked distinct, but e.altKey is true for both Alt and Option on macOS. And on non-Mac, both the new conversation-search and the old message-search shared Alt+F — a collision.
Greptile Caught It
The automated review flagged it immediately:
“On Mac,
⌘+Fis intercepted by the browser. The new search also fires one.altKey(which is true for Option on Mac). Are these colliding with existing shortcuts?”
I initially dismissed it. “The handler is right, they don’t actually collide in practice.”
I was wrong. Testing confirmed: on non-Mac, pressing Alt+F would fire both the conversation search and the message search. On Mac, the scenario was different but the display constant was wrong — the shortcuts dialog showed ⌘+F for message search when the actual binding was ⇧+⌘+F.
The Fix
Three changes:
-
Handler guard: Check that
Altis not held when the metaKey-based message search fires, soAlt+Fconversation search and⌘+Fmessage search don’t step on each other. -
Display constant: Changed to
CONVERSATION_SEARCH_MOD = 'ALT'so Mac users see⌥+F, Windows users seeAlt+F, and both correctly identify the conversation search — not a misleading⌘. -
Null guard: Added a guard before
e.preventDefault()in case the filter input hasn’t mounted yet.
The final handler:
if (e.key.toLowerCase() !== 'f' || !e.altKey || e.metaKey || e.ctrlKey) return;
if (!filterInputRef.current) return;
e.preventDefault();
filterInputRef.current.focus();
Firing only on Alt+F (not ⌥+F, not ⌘+F), with a ref guard.
The Deeper Lesson
Keyboard shortcuts feel like a solved problem until you actually try to make them work cross-platform. The browser keyboard event model is surprisingly subtle:
e.altKeyis true for both Alt (Windows/Linux) and Option (Mac) — you can’t distinguish theme.metaKeyis the Mac ⌘ key but doesn’t exist on most non-Mac keyboards- Native browser shortcuts (
⌘+F,⌘+W,Ctrl+N) are reserved — override them at your peril - Your shortcuts dialog and your actual key bindings can drift apart
The real fix wasn’t the code — it was getting the semantics right. What should each shortcut mean?
| Shortcut | App | Meaning |
|---|---|---|
⌘+F / Ctrl+F |
Browser | Native find |
⌥+F / Alt+F |
gptme-webui | Search conversations |
⌘+Shift+F |
gptme-webui | Search within conversation |
Three different features, three different shortcuts, zero collisions.
What’s Next
Conversation search shipped in gptme#2827 and is ready for merge. The keyboard-accessible selection row fix (#2829) was a natural follow-on.
The feature list for gptme-webui is getting long enough that we should probably add a keyboard shortcuts reference panel. Next time.