A drop-in block that adds keyboard shortcuts to any OutSystems Reactive Web app. Register Ctrl+S, Esc, /, Ctrl+K — anything you like — and get a single event when the user presses one. Ignores keystrokes while typing in inputs by default, prevents browser defaults (no more "Save Page As" popping up), and cleans itself up on navigation. Pure client-side, no dependencies.
Ctrl+S
Esc
/
Ctrl+K
Power users work with keyboards, and every desktop-class app supports shortcuts. Ctrl+S to save, Esc to close a modal, / to focus search, Ctrl+K to open a command palette — these are the small details that make an app feel finished. OutSystems doesn't ship a first-class way to wire them, so most apps just skip them.
This block fixes that. You give it a list of shortcut strings, handle its OnShortcut event, and switch on the shortcut name to run whatever action you want. That's the whole integration.
OnShortcut
OnShortcut(Shortcut)
ctrl
alt
shift
meta
esc
space
up
down
left
right
.oap
For shortcuts to work on every screen of your app, place the KeyboardShortcuts block once on your shared Layout. Because its keydown listener is attached to the document, one instance is all you need — it works from any screen the layout serves.
KeyboardShortcuts
If you only want shortcuts on a specific screen, place the block on that screen instead. Don't place it multiple times per app; that would just attach and immediately replace the listener, wasting work.
KeyboardShortcuts Shortcuts = ["ctrl+s", "esc", "/", "ctrl+k"] AllowInInputs = False Handle OnShortcut(Shortcut): Switch Shortcut: "ctrl+s" → run SaveDraft action "esc" → close current modal "/" → focus the search input "ctrl+k" → open the command palette
Drop the block, set the list, handle the event with a Switch. The block does the rest.
Switch
Shortcuts
ctrl+s
AllowInInputs
False
Shortcut
Modifiers are joined with +, in any order, followed by the key. Case doesn't matter; whitespace is stripped.
+
Modifiers: ctrl, alt, shift, meta (meta is Cmd on Mac, Windows key on Windows/Linux).
Keys: any letter, digit, or symbol as it appears on the keyboard: a, s, 1, /, ?, ,, .. Plus these friendly aliases for special keys: esc, space, up, down, left, right.
a
s
1
?
,
.
Examples: ctrl+s, Ctrl+S, shift+/, alt+enter, ctrl+shift+k, esc, /, ?.
shift+/
alt+enter
ctrl+shift+k
By default, the block ignores keystrokes when the user's focus is on an input, textarea, select, or contenteditable element. This is intentional — you almost never want / to trigger "focus search" while the user is typing "9/11" into a field, or Esc to close a modal in the middle of editing.
If you do want a shortcut to work even while typing (rare — usually only for Ctrl-modified shortcuts like Ctrl+S), set AllowInInputs = True. Note that this applies to all registered shortcuts, not per-shortcut; per-shortcut control is a candidate for v2 if there's demand.
Ctrl
AllowInInputs = True
When a registered shortcut matches, the block calls preventDefault() on the event. This is what stops Ctrl+S from opening "Save Page As," Ctrl+K from opening the browser search bar, and so on. If a shortcut isn't registered, the browser handles it normally — the block doesn't interfere.
preventDefault()
If you want a shortcut to fire and let the browser do its thing (rare), don't register it and handle the raw keydown yourself. But almost always, when you register a shortcut you want to own it.
Mac users press Cmd for what Windows users press with Ctrl. This block reports them as separate modifiers (meta on Mac Cmd, ctrl on Windows Ctrl), so if you want a shortcut to work on both, register both:
Shortcuts = ["ctrl+s", "meta+s"] Handle OnShortcut(Shortcut): If Shortcut in ["ctrl+s", "meta+s"] → save
A v2 could add a mod+s alias meaning "Ctrl on Windows, Cmd on Mac" — for now, registering both explicitly is the cross-platform pattern.
mod+s
The shortcut doesn't fire.Confirm the block is on a screen that's actually loaded (usually the shared Layout). Also check AllowInInputs if you're testing while focused on an input. Most importantly: check the shortcut string exactly matches your registration — "Ctrl+S" and "ctrl+s" both work (case-insensitive), but "Ctrl + S" with spaces also works (whitespace is stripped), while typos like "cntrl+s" won't match.
"Ctrl+S"
"ctrl+s"
"Ctrl + S"
"cntrl+s"
The shortcut fires but so does the browser action.Confirm the shortcut is actually in your Shortcuts list — the block only prevents the default for registered shortcuts. If the browser's action is still happening for a registered shortcut, another script on the page might be intercepting the event first; check your other JavaScript.
Shortcuts fire twice.The block guards against duplicate listeners internally, but if you placed the block on the Layout and on a specific screen, you'd have two instances. Place it only once per app.
Nothing works after navigating between screens.The block cleans up its listener on destroy and reattaches on the next screen's ready — if you've customized the block's lifecycle actions, verify On Destroy still calls Cleanup and On Ready still calls Setup.
Users on Mac say Cmd+S doesn't work.Mac Cmd is meta, not ctrl. Register both ctrl+s and meta+s (see section 10).
meta+s
AllowInInputs = False
ctrl+
meta+
Ctrl+T
Ctrl+W
Ctrl+N
Published on the OutSystems Forge as open, reusable code. Free to use and adapt in your OutSystems projects.