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.

Published October 2, 2026 Updated October 2, 2026 7 min read
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.

Manifest modifiers and the keys they meanCtrl, Command, MacCtrl, Alt and Shift in manifest suggested_key values and the physical key each maps to on Windows/Linux and macOS.Manifest tokenWindows / LinuxmacOSNotesCtrlCtrl⌘ CommandMost portableCommand—⌘ Commandmac entry onlyMacCtrl—⌃ Controlmac entry onlyAltAlt⌥ OptionTyping risk on MacCtrl+AltRejectedRejectedAltGr conflict
On Mac, Ctrl in the manifest means ⌘; MacCtrl means the Control key.

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.

Picking a modifier for a new commandDecision tree: for an action used while typing in text fields, prefer Ctrl/Command plus Shift; for a page-level toggle, Alt plus Shift on Windows and MacCtrl plus Shift on Mac; avoid Alt alone on Mac and Ctrl plus Alt everywhere.Where will the user press it?while typingCtrl/⌘ + Shift + keywon't insert characterspage-level toggleAlt+Shift / ⌃⇧per-platform entriesavoidCtrl+Alt, ⌥+keyAltGr, special chars
Shift plus one primary modifier is the safest pattern.

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.

Two systems, one mental modelManifest commands use Ctrl to mean Command on Mac and are handled by the browser, firing commands.onCommand; in-page shortcuts use DOM keydown where ctrlKey is the physical Control key and metaKey is Command; a helper maps both to a primary modifier.Manifest "Ctrl"→ ⌘ on MacBrowser handlesglobalcommands.onCommandservice workersame user intentDOM keydownctrlKey ≠ ⌘ on MacisPrimaryModifier(e)metaKey on MacPage-level handlercontent script
Normalise to "primary modifier" so both systems agree.

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 Ctrl is Control on Mac. It is ⌘; use MacCtrl for Control.
  • Checking e.ctrlKey for “Cmd” on Mac. Use metaKey.
  • ⌥-letter shortcuts on Mac. They type characters in text fields.
  • Matching e.key with Option held. It is a special character; use e.code.
  • Ctrl+Alt combinations. Rejected because of AltGr.

Cross-browser variation

  • Chrome / Edge: mapping as described; mac, windows, linux, chromeos and default keys.
  • Firefox: same suggested_key platforms (default, mac, linux, windows, chromeos, android, ios); MacCtrl supported; some combinations reserved differently by Firefox.
  • Safari: commands follow macOS conventions; ⌘ combinations frequently collide with Safari’s own menu shortcuts — test carefully.

Verification

  1. Install in a clean profile on macOS and Windows; confirm the assigned shortcuts in the shortcuts page match your per-platform entries.
  2. On Mac, press ⌥⇧R in a text field and confirm no character is typed and the command fires (or switch to ⌃⇧R).
  3. On a German keyboard layout, confirm in-page shortcuts matched by e.code still work.
  4. 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.

Other UI/UX Patterns & Interactive Components Resources