There are various ways to listen to keyboard events in Elm. If you want to get all keyboard events, you can subscribe using functions from Browser.Events. And, if you want to get keyboard events for specific HTML elements, you can use Html.Events.on.
Each of those functions asks you to provide a Decoder msg
to convert the
keyboard event into a message your application can handle. To help you along
the way, Html.Events
has a handy
keyCode
decoder. You can use it to turn the keyboard event into a keycode -- which you
can then map into a message your app understands.
However, there is more information available in a keyboard event than just the keycode. So, we provide a decoder which gives you all the available information:
type alias KeyboardEvent =
{ altKey : Bool
, ctrlKey : Bool
, key : Maybe String
, keyCode : Key
, metaKey : Bool
, repeat : Bool
, shiftKey : Bool
}
Even better, we:
normalize some browser-specific quirks, such as where to look for the keyCode (under "keyCode", "which" or "charCode")
turn the keyCode into a type-safe Key
value.
But wait, there's more! We also have a version of the keyboard event decoder which allows you to filter events right in the decoder. That way, you can prevent some events from reaching your update function at all, which can be useful in some scenarios.
To listen for keyboard events on HTML elements, you can do something like this:
div
[ on "keydown" <|
Json.Decode.map HandleKeyboardEvent decodeKeyboardEvent
, tabindex 0
, id "id-for-auto-focus"
, style [ ( "outline", "none" ) ]
]
[]
We use thetabIndex
attribute to make the element focusable, since an HTML
element must be focusable in order to receive keyboard events. And, we provide
an id
in case we want to programmatically focus on the element, via
Browser.Dom.focus.
For complete examples, see:
To listen for keyboard events globally, you can use functions from Browser.Events to subscribe to all keyboard events. For an example, see
{ altKey : Basics.Bool
, ctrlKey : Basics.Bool
, key : Maybe String
, keyCode : Keyboard.Key.Key
, metaKey : Basics.Bool
, repeat : Basics.Bool
, shiftKey : Basics.Bool
}
A representation of a keyboard event.
The key
field may or may not be present, depending on the listener ("keydown"
vs. "keypress" vs. "keyup"), browser, and key pressed (character key vs.
special key). If not present, it will be Nothing
here.
The keyCode
is normalized by decodeKeyboardEvent
to use whichever of
which
, keyCode
or charCode
is provided, and made type-safe via
Keyboard.Key
(see the excellent SwiftsNamesake/proper-keyboard for
further manipulation of a Key
).
decodeKeyboardEvent : Json.Decode.Decoder KeyboardEvent
Decodes a KeyboardEvent
from a keyboard event.
considerKeyboardEvent : (KeyboardEvent -> Maybe msg) -> Json.Decode.Decoder msg
You provide a function which, given a KeyboardEvent
, turns it into a
message your update
function can handle. You get back a Decoder
for those
messages.
When your function returns Nothing
, the decoder will fail. This means that
the event will simply be ignored -- that is, it will not reach your update
function at all.
Essentially, this allows you to filter keyboard events inside the decoder
itself, rather than in the update
function. Whether this is a good idea or
not will depend on your scenario.
Some lower-level helpers that you might find useful.
Basics.Int
A type alias for Int
.
decodeKeyCode : Json.Decode.Decoder KeyCode
Decodes keyCode
, which
or charCode
from a keyboard event
to get a numeric code for the key that was pressed.
decodeKey : Json.Decode.Decoder (Maybe String)
Decodes the key
field from a keyboard event.
Results in Nothing
if the key
field is not present, or blank.