Keyboard shortcuts
How to design, build, and document accessible keyboard shortcuts at GitHub.
Keyboard shortcuts let people trigger an action with one or more keys instead of navigating to a control and activating it. Used well, they make power users faster and give people who rely on the keyboard a quicker path through the product. Used poorly, they conflict with the browser, the operating system, or assistive technology, and become an accessibility barrier.
This page covers how to decide on, design, and document a shortcut. For the canonical engineering implementation at GitHub, see the Keyboard shortcuts guide in The Hub (Internal only), which documents how to use ui-commands, our internal library centralizing all keyboard shortcuts in React-based UI.
A keyboard shortcut is an enhancement, and should never be the only way to do something. Every action a shortcut triggers must also be reachable by navigating to a focusable control and activating it with Enter or Space.
Relevant WCAG success criteria
Two success criteria shape almost every decision on this page:
- 2.1.1 Keyboard (Level A) — All functionality must be operable through a keyboard. A shortcut is an addition to keyboard operability, not a substitute for it.
- 2.1.4 Character Key Shortcuts (Level A) — If a shortcut uses only a single character key (a letter, number, punctuation, or symbol), at least one of the following must be true: The shortcut can be turned off, it can be remapped to use a non-printable key such as Ctrl or Alt, or it is only active when the relevant component has focus.
When to add a shortcut
Add a shortcut when it speeds up a frequent, deliberate action for people who already know the interface. Reach for one when:
- The action is common enough that repeating the point-and-click path is a real cost.
- The action has a clear, stable meaning that won't surprise people.
- The shortcut won't collide with the browser, the OS, or assistive technology (see Avoiding conflicts).
Avoid a shortcut when the action is rare, destructive without confirmation, or only meaningful in a narrow context. A growing list of obscure shortcuts adds cognitive load and increases the chance of a conflict.
Designing the shortcut
Avoid single-character shortcuts by default
Single-character shortcuts (for example, pressing r to reply) are the most common cause of accessibility failures. People who use speech input or who have motor disabilities frequently trigger them by accident, because the keys that fire them are the same keys used to type. People who use a screen reader may have those keys intercepted before the page ever sees them.
If you use a single-character shortcut, you must satisfy 2.1.4 by doing at least one of the following:
- Provide a setting to turn shortcuts off.
- Let people remap the shortcut to include a modifier key.
- Make the shortcut active only while the relevant component has focus (not globally).
GitHub already offers a global Accessibility settings option to disable character key shortcuts. New single-character shortcuts must respect that setting.
Prefer modifier-based or focus-scoped shortcuts
A shortcut that combines a printable key with a non-printable modifier (Ctrl, Alt, ⌘) is far less likely to fire by accident and is exempt from the single-character requirement. When a shortcut only makes sense inside one component—a menu, a tree view, a rich-text editor—scope it to that component's focus rather than registering it globally.
Avoiding conflicts
A shortcut must not conflict with existing keyboard shortcuts in the browser, the operating system, or assistive technologies. This is a required check in Primer's accessibility engineering review (Internal only).
- Assistive technology: screen readers reserve many single keys for navigation (headings, landmarks, forms). Test with at least one screen reader on each platform you support—for example, VoiceOver on macOS, and NVDA or JAWS on Windows.
- Browser and OS: avoid common combinations such as Ctrl/⌘ + W, T, N, F, and L.
- Within GitHub: check the existing registry before adding a new binding so you don't shadow or duplicate one.
Use familiar, consistent keys
Match platform conventions where they exist (⌘ on macOS, Ctrl on Windows and Linux). Keep meanings consistent across the product so that a shortcut does the same kind of thing wherever it appears.
Making shortcuts discoverable
A shortcut that nobody can find helps no one. Make shortcuts discoverable through more than one channel:
- A shortcut help dialog. GitHub exposes a full list of shortcuts when you press ?. Any new shortcut should appear there.
- Inline hints. Surface the shortcut where the action lives—for example, in a tooltip on the control or next to a menu item.
- Programmatic exposure. Use
aria-keyshortcutson the element the shortcut acts on so assistive technology can announce it. Primer component APIs document this with thekeyshortcuts/aria-keyshortcutspattern (see the IconButton and TreeView APIs). - Keep discoverability in sync with the disable setting. When character key shortcuts are turned off in Accessibility settings, the ? help dialog and any inline hints should reflect that the shortcut is inactive, so people aren't shown a binding that won't fire.
When you render a key in the UI or in docs, wrap it in a <kbd> element (for example: Ctrl + K) so it is styled and announced as a key.
aria-keyshortcuts only advertises the shortcut to assistive technology—it does not implement the behavior. The reverse is also true: wiring up the key handler does not expose the shortcut to assistive technology. You need both, and you still have to satisfy 2.1.4 if it's a single-character shortcut.
The value syntax for aria-keyshortcuts is not the same as github/hotkey's data-hotkey. aria-keyshortcuts uses space-separated alternatives with +-joined chords and full key names (for example: Control+K Meta+K), while data-hotkey uses its own format (for example: Mod+k). Don't copy the same string into both attributes—set each one in its own syntax.
Implementing at GitHub
The preferred implementation in the monolith pairs a Rails helper with github/hotkey:
- Register the shortcut in
DEFAULT_KEYBOARD_SHORTCUTSso it appears in the help dialog and respects the global disable setting. - Bind it in markup with
KeyboardShortcutsHelper::hotkeys_for, which emits thedata-hotkeyattribute thatgithub/hotkeylistens for. - Add
aria-keyshortcutsto the target element so the binding is exposed to assistive technology.
The full, up-to-date steps live in The Hub's keyboard shortcuts guide (Internal only), owned by ui-and-monolith-platform. Treat that page as the source of truth for engineering details; this page is the source of truth for the design and accessibility requirements.
Checklist
Before shipping a shortcut, confirm that it:
- Triggers an action that is also reachable without the shortcut (2.1.1).
- Either avoids single-character bindings, or can be disabled, remapped, or is focus-scoped (2.1.4).
- Does not conflict with the browser, OS, or assistive technology.
- Appears in the ? help dialog.
- Exposes itself with
aria-keyshortcutsand, where helpful, an inline hint. - Has been tested with a screen reader on each supported platform (for example: VoiceOver, plus NVDA or JAWS).