React Keyboard event handling

Does anyone have any experience with keyboard event handling? I am trying to add an event handler that moves to the first or last item in a list when the home and end keys are pressed. I looked a the [rescript-react/ReactEvent.res at master · rescript-lang/rescript-react · GitHub](https://ReactEvent source code) and checked Stack Exchange but, I don’t see anyway to do this natively in Rescript/react.

You’d listen to the onKeyDown event and then use the ReactEvent.Keyboard module to get access to the information you are interested in.

Here is a codesnippet to draft the rough idea:

@react.component
let make = () => {
  let onKeyDown = evt => {
    let key = ReactEvent.Keyboard.key(evt)

    switch key {
    | "HOME" =>
      Js.log("home was pressed")
      ReactEvent.Keyboard.preventDefault(evt)
    | "END" =>
      Js.log("end was pressed")
      ReactEvent.Keyboard.preventDefault(evt)
    | _ => ()
    }
  }
  
  <div onKeyDown> <input type_="text" /> </div>
}

Playground Link

Here are some notes:

  • Use the ReactEvent.Keyboard module to get access to the event information passed as the evt object
  • Use ReactEvent.Keyboard.preventDefault(evt) to prevent default behavior on e.g. the input field when pressing specific buttons (useful if you want to take care of the event logic yourself instead of letting the html input do its thing)
  • Use the MDN KeyboardEvent.key docs to find all relevant information about the key values

Lastly, we actually used keyboard events in the ReScript playground as well, like here, if you are keen on reading other ppl’s code.

4 Likes

Thanks, I think I must have been using ReactEvent.Keyboard.KeyCode(evt) because I wrote almost exactly this yesterday but did not see how to map the inter I was seeing to key names.

:slightly_smiling_face:

@ryyppy Thanks again for your help. I have another question. In my implementation, I am getting a compiler error stating

This has type: {..}
    Somewhere wanted: array<'a>

when I uncomment line 37 in this playground.

I see from the ReactEvent code ReactEvent.Keyboard,target(evt) returns {…} but I cannot find documentation that explains how to access the fields of the returned object. I have looked at the options for binding to JS objects and tried to bind using a Rescript object. I also looked at theJS documentation for React Synthetic Event target and native Dom.EventTarget. It’s not obvious how to paremeterize the selector as I am trying to do in the playground. Thoughts? Thanks.

I suspect the object access syntax needs a literal string rather than a variable.

I.e. change this:

let id = target[selector]

to this:

let id = target["id"]

Edit: And you might need to do something like this to convert back to an int (which I think is what you need?):

let id = target["id"]->Belt.Int.fromString

To add to that, objects in ReScript cannot be dynamically accessed. The keys must be statically known at compile time to guarantee type safety. the target[selector] syntax only works on arrays, not objects (which is what the error message is trying to say).

1 Like

It was my suspicion the object could only be accessed with a literal. I’m trying to do this in a way that avoids hardcoding a single literal - at another time, “key” might make more sense. It sounds like my only option, at least for now, is a variant for the selector argument that I then use to select a specific literal access. Opinions desired.

Thanks @stephanie

An option you might consider is to pass a selector function instead of a selector name string:

let onKeyDownFactory = (items, selector) => {
  let id = selector(target)
}

let selector = target => 
  target["id"]
  ->Belt.Int.fromString
  ->Belt.Option.getWithDefault(0)

<div onKeyDown={onKeyDownFactory(items, selector)} >

This helps keep hard-coded attribute names out of the onKeyDownFactory function, which I think was your original intention?

A selector function meets my needs perfectly. Thank you.

If anyone is interested, I updated the playground to use a selector function