Key Handling Overview
To handle keyboard input in Slint, use the FocusScope with KeyBinding elements or individual key-pressed and key-released callbacks in various elements.
Keyboard input is delivered via KeyEvent data structures.
The primary field of this data structure is the text property, which holds all affected keys
encoded in a string.
Use the Key namespace to identify known named keys.
See the Key Bindings section for how to handle key bindings declaratively with
Slint’s KeyBinding elements and the built-in keys type, which is constructed from the @keys macro.
KeyEvent
Section titled “KeyEvent”This structure is generated and passed to the key press and release callbacks of the FocusScope element.
text(string): The unicode representation of the key pressed.modifiers(KeyboardModifiers): The keyboard modifiers active at the time of the key press event.repeat(bool): This field is set to true for key press events that are repeated, i.e. the key is held down. It’s always false for key release events.
Key Bindings
Section titled “Key Bindings”Use the KeyBinding element inside a FocusScope to declare key bindings (or keyboard shortcuts).
The KeyBinding’s keys property takes an instance of the keys type and invokes the activated callback when the key combination is detected.
The keys type represents a key, combined with modifiers and is constructed with the @keys macro.
Key bindings in Slint are based on logical keys — the character a keypress produces on the current keyboard layout — not the physical position of a key.
This means, for example, that @keys(Control + Z) activates when the user presses the key that produces z on their layout, regardless of where that key sits on the keyboard.
As a consequence, numpad digit keys are not distinguished from the main row digit keys, and AltGr isn’t available as a modifier (it is consumed by the OS to produce characters).
The @keys(..) macro accepts a key from the Key namespace, combined with any of these modifiers:
Meta(⌃ control on macOS and Windows key on PC)Control(⌘ command on macOS)ShiftAlt(⌥ option on macOS)
export component Example inherits Window { forward-focus: scope;
scope := FocusScope { KeyBinding { keys: @keys(Control + Q); activated => { debug("Quit shortcut activated"); } }
KeyBinding { keys: @keys(Control + S); activated => { debug("Save shortcut activated"); } }
Text { text: scope.has-focus ? "Press Control + Q or Control + S" : "Click to focus"; } }}Different Keyboard Layouts
Section titled “Different Keyboard Layouts”Different keyboard layouts are handled automatically by the @keys(..) macro for keys from the Key namespace.
For example, @keys(Control + Plus) fires whenever the user presses the key that produces + on their layout — on a US layout that requires Shift + =, while on a German layout + has its own key and no Shift is needed.
Named keys inside @keys(..) are logical: A represents the character a, not a specific physical key location. This means @keys(Control + A) will activate on whichever key produces a on the user’s layout, regardless of where that key sits on the keyboard.
If you need to define a key binding that involves a key outside of the Key namespace, continue reading the next section which covers advanced key definitions.
Advanced Key Bindings
Section titled “Advanced Key Bindings”If possible, prefer to use a key from the Key namespace inside @keys(..).
If you absolutely need to define a binding to a different key, you can use a string literal inside the @keys(..) macro.
For example: @keys(Control + "ä").
Note though that the @keys(..) macro no longer automatically handles different keyboard layouts and Shift behavior in this case.
The provided string is simply matched against the lowercased text, plus the modifiers of the given KeyEvent
To prevent issues with characters that entirely change their keycode when Shift (or sometimes Alt on macOS) is applied, you can mark these modifiers as optional with a trailing ?, e.g.:
Shift?Alt?
When a modifier is marked as optional, the keys will ignore the state of the corresponding modifier when matching.
For example, to support key bindings that produce a Euro-Sign (€), add both Shift? and Alt?: @keys(Control + Shift? + Alt? + "€").
This will allow your users to reach the binding on almost all keyboard layouts that have a key with this label.
As another example, @keys(Control + Plus) is equivalent to @keys(Control + Shift? + "+").
Key Namespace
Section titled “Key Namespace”The Key namespace contains a list of well-known logical key codes (including any non-printable characters).
Key names in this namespace identify keys by the character they produce, not by their physical position on the keyboard.
For example, Key.A represents the character a, not the top-left letter key of a QWERTY keyboard.
Note that alphabetic keys (e.g. Key.A-Key.Z) are represented as lowercase (e.g. “a”-“z”).
Make sure to case-convert the KeyEvent text or the Key as necessary.
BackspaceTabReturnEscapeBacktabDeleteShiftControlAltAltGrCapsLockShiftRControlRMetaMetaRSpaceUpArrowDownArrowLeftArrowRightArrowF1F2F3F4F5F6F7F8F9F10F11F12F13F14F15F16F17F18F19F20F21F22F23F24InsertHomeEndPageUpPageDownScrollLockPauseSysReqStopMenuBackABCDEFGHIJKLMNOPQRSTUVWXYZDigit0Digit1Digit2Digit3Digit4Digit5Digit6Digit7Digit8Digit9CircumflexExclamationDoubleQuoteHashDollarPercentAmpersandUnderscoreOpenParenCloseParenAsteriskPlusPipeHyphenMinusOpenCurlyBracketCloseCurlyBracketTildeColonSemicolonLessThanEqualsGreaterThanQuestionMarkAtCommaPeriodSlashBackQuoteOpenBracketBackSlashCloseBracketQuote
© 2026 SixtyFPS GmbH