Mac and Windows Modifier Keys in Commands
Declare and display extension shortcuts that work on macOS, Windows, Linux and ChromeOS: Ctrl versus Command versus MacCtrl, per-platform suggested_key, allowed key combinations, Alt-key pitfalls, and showing the right symbols.
Table of Contents
The manifest says "default": "Ctrl+Shift+Y". On Windows it works. On a Mac, Chrome maps Ctrl to the Command key, so the shortcut becomes ⇧⌘Y — which may be exactly what you wanted, or may collide with a system or app shortcut you never tested. Meanwhile, the in-page shortcut your content script listens for checks event.ctrlKey, which on a Mac is the physical Control key, not Command, so the two halves of your extension disagree about which key is which. Modifier keys are the most platform-specific part of keyboard handling, and extensions have two systems to get right: manifest commands and DOM key events. This guide maps both. It belongs to keyboard shortcuts and commands.
How Chrome maps modifiers
In the commands section of the manifest, suggested_key accepts per-platform entries: default, windows, mac, linux and chromeos. A shortcut must include Ctrl or Alt (on Mac, Command, Ctrl or Option/Alt variants as described below), optionally Shift, plus one key — a letter, digit, function key, or named key such as Comma, Period, Home, Space or arrow keys. On macOS, Chrome translates Ctrl in the manifest to the Command key (⌘); to mean the physical Control key on a Mac you write MacCtrl. Alt on Mac is Option (⌥). Combinations using only Shift, or more than one non-modifier key, are not allowed. Ctrl+Alt combinations are rejected because they collide with AltGr on many keyboard layouts.
Step-by-step: shortcuts that work on every platform
1. Write per-platform suggestions
1"commands": {
2 "save-page": {
3 "suggested_key": {
4 "default": "Ctrl+Shift+Y",
5 "mac": "Command+Shift+Y",
6 "chromeos": "Ctrl+Shift+Y"
7 },
8 "description": "__MSG_cmdSavePage__"
9 },
10 "toggle-reader": {
11 "suggested_key": { "default": "Alt+Shift+R", "mac": "MacCtrl+Shift+R" },
12 "description": "__MSG_cmdToggleReader__"
13 }
14}
Execution context: the manifest. An explicit mac entry documents intent and lets you choose a different combination where the default would collide. Alt+Shift+letter is often free on Windows and Linux; on Mac, ⌥⇧letter types special characters in text fields, so MacCtrl+Shift+letter (⌃⇧R) is a safer Mac equivalent.
2. Avoid reserved and conflicting combinations
1shortcut-checklist.md
2✗ Ctrl+T, Ctrl+W, Ctrl+N, Ctrl+L, Ctrl+Tab — browser reserves these; extensions cannot take them
3✗ Ctrl+Alt+anything — rejected (AltGr)
4✗ Command+Q, Command+H, Command+M — macOS system shortcuts
5✗ Alt+letter on Mac — types characters (å, ß…)
6✓ Ctrl+Shift+<letter> / Command+Shift+<letter>, Alt+Shift+<letter> / MacCtrl+Shift+<letter>
Execution context: a design checklist. Chrome refuses to assign shortcuts that collide with browser-reserved ones and skips any already taken by another extension. Check the candidate in a clean profile on each platform. See resolving keyboard shortcut conflicts.
3. Match the DOM modifier to the platform
1// content script or extension page
2const isMac = navigator.userAgentData?.platform === "macOS" || /Mac/.test(navigator.platform);
3
4export function isPrimaryModifier(e) {
5 return isMac ? e.metaKey : e.ctrlKey; // ⌘ on Mac, Ctrl elsewhere
6}
7
8document.addEventListener("keydown", (e) => {
9 if (isPrimaryModifier(e) && e.shiftKey && e.code === "KeyY") { e.preventDefault(); toggleOverlay(); }
10}, true);
Execution context: content scripts and extension pages. In DOM events, ctrlKey is the physical Control key on every platform and metaKey is ⌘ on Mac — the opposite of the manifest’s mapping. A helper that picks the “primary” modifier per platform keeps in-page shortcuts consistent with manifest commands. Use e.code (physical key position) for letter shortcuts so they work on non-QWERTY layouts with the same finger position, or e.key when the character matters.
4. Choose code or key deliberately
1// e.code — physical key: "KeyZ" is the same position on QWERTY and QWERTZ (where it prints "Y")
2// e.key — produced character: "z" on QWERTY, "y" at that position on QWERTZ; with Shift, "Z"
3// With ⌥ on Mac, e.key is the special character ("Ω" for ⌥Z), so match Alt shortcuts on e.code
4if (e.altKey && e.shiftKey && e.code === "KeyR") toggleReader();
Execution context: in-page key handlers. Option-modified keys on a Mac produce special characters in e.key, so e.key === "r" never matches ⌥⇧R. Matching on e.code avoids this. For punctuation shortcuts like “?” that users think of by character, e.key is better.
5. Display the right symbols
1const MAC_SYMBOLS = { Ctrl: "⌃", MacCtrl: "⌃", Command: "⌘", Alt: "⌥", Shift: "⇧" };
2
3export function displayShortcut(parts) { // parts: ["primary", "Shift", "Y"]
4 if (isMac) return parts.map((p) => p === "primary" ? "⌘" : MAC_SYMBOLS[p] ?? p).join("");
5 return parts.map((p) => p === "primary" ? "Ctrl" : p).join("+");
6}
7// displayShortcut(["primary","Shift","Y"]) → Mac "⌘⇧Y", Windows "Ctrl+Shift+Y"
Execution context: extension UI for in-page shortcuts you define yourself. For manifest commands, use the string from commands.getAll, which Chrome already formats per platform. Mac convention orders modifiers ⌃⌥⇧⌘ and omits separators. See showing shortcut hints in extension UI.
6. Handle ChromeOS and Linux specifics
ChromeOS reserves many Ctrl+Alt and Search combinations, and Linux desktop environments claim some Ctrl+Alt and Super combinations globally. Stick to Ctrl+Shift and Alt+Shift there, and provide a chromeos entry when its default should differ. Global shortcuts ("global": true) are limited to Ctrl+Shift+[0-9] and are not available on ChromeOS; see implementing global keyboard shortcuts safely.
7. Test on real keyboards
Test each suggested shortcut on each platform with a clean profile and with common keyboard layouts — US, UK, German (QWERTZ), French (AZERTY). Shortcuts on number keys behave differently on AZERTY, where digits need Shift. If a shortcut is awkward on a major layout, choose another.
8. Document shortcuts per platform
1help/shortcuts.md
2| Action | Windows / Linux | macOS |
3|-----------------|-------------------|--------|
4| Open popup | Alt+Shift+R | ⌃⇧R |
5| Save page | Ctrl+Shift+Y | ⌘⇧Y |
6| Toggle reader | Alt+Shift+F | ⌃⇧F |
Execution context: the extension’s help page or store listing. Users read help on one platform and use another, so publish both columns, and add a note that shortcuts can be changed in the browser’s settings — the defaults are only the starting point.
Common mistakes
- Assuming manifest
Ctrlis Control on Mac. It is ⌘; useMacCtrlfor Control. - Checking
e.ctrlKeyfor “Cmd” on Mac. UsemetaKey. - ⌥-letter shortcuts on Mac. They type characters in text fields.
- Matching
e.keywith Option held. It is a special character; usee.code. Ctrl+Altcombinations. Rejected because of AltGr.
Cross-browser variation
- Chrome / Edge: mapping as described;
mac,windows,linux,chromeosanddefaultkeys. - Firefox: same
suggested_keyplatforms (default,mac,linux,windows,chromeos,android,ios);MacCtrlsupported; some combinations reserved differently by Firefox. - Safari: commands follow macOS conventions; ⌘ combinations frequently collide with Safari’s own menu shortcuts — test carefully.
Verification
- Install in a clean profile on macOS and Windows; confirm the assigned shortcuts in the shortcuts page match your per-platform entries.
- On Mac, press ⌥⇧R in a text field and confirm no character is typed and the command fires (or switch to ⌃⇧R).
- On a German keyboard layout, confirm in-page shortcuts matched by
e.codestill work. - Confirm displayed hints use symbols on Mac and words elsewhere.
FAQ
Can I use the Fn or Globe key?
No. They are not available as modifiers to extensions.
Can I suggest a shortcut with just a function key?
Function keys alone are not allowed in Chrome commands; combine them with a modifier. Media keys (MediaPlayPause and similar) are allowed alone.
Why did my Mac shortcut become ⌘ when I wrote Ctrl?
Because Chrome maps Ctrl to Command on Mac. Write MacCtrl for the Control key.
Related
- Resolving keyboard shortcut conflicts — when keys are taken.
- Handling shortcuts in content scripts — DOM key handling.
- Shortcut behaviour in Firefox and Safari — engine differences.
- Keyboard shortcuts and commands — the parent topic.