---
title: Keyboard
---

import { Badge } from '@astrojs/starlight/components'

The keyboard object provides an easy to use way to set up keys to perform different actions in your UI. It also allows you to create key combinations with ease. It also provides two properties for adding and removing key actions.

:::note
 In version 2.4.4 we added support for registering multiple callbacks for the same key combination and type, allowing for more flexible event handling.
:::

## .on(options)

Sets up a key action. You can add multiple actions with a single `.on` call.

```ts
type KeyboardOptions = {
    keys: (string | number)[];
    callback: string | ((event: KeyboardEvent) => void);
    type?: KeyboardEventType | KeyboardEventType[];
};

keyboard.on(options: KeyboardOptions)
```

### options

#### keys

Type:

```ts
type keys = (string | number)[]
```

The `keys` array are the keys that will trigger the callback. Putting multiple keys will treat them as a key combination. The keys are normalized, so duplicates are removed and keycodes are converted to key names.

For example, the following code will trigger the callback when pressing 'A', 'B' and 'C' keys on the keyboard at the same time

```ts
keyboard.on({
    keys: ['A', 'B', 'C'],
    callback: () => {},
})
```

Apart from using strings for keys, you can also use keycodes or the 'KEYS' global object. The `KEYS` object is available on the `window` object and contains all the available key names and keycodes.

```ts
keyboard.on({
    keys: [65, 66, 67],
    callback: () => {},
})
```

```ts
keyboard.on({
    keys: [KEYS.A, KEYS.B, KEYS.C],
    callback: () => {},
})
```

#### callback

Type:

```ts
type callback = ((event: KeyboardEvent) => void) | string
```

The `callback` property is the function that will be triggered when the keys from the `keys` array are pressed. The `KeyboardEvent` is passed as a parameter to the callback.

You can either write your function inside the object

```ts
keyboard.on({
    keys: ['A', 'B', 'C'],
    callback: (event: KeyboardEvent) => doSomething(event),
});
```

or if you have a registered action, you can pass it here

```ts
keyboard.on({
    keys: ['A', 'B', 'C'],
    callback: 'registered-action',
});
```

#### type

Type:

```ts
type type = KeyboardEventType | KeyboardEventType[]
```

The `type` property shows the type of key interaction that the callback will be triggered on. You can pass the following interaction types: `press`, `hold` and `lift`.

This example will trigger the callback on a key press. If you press and hold the key it will only trigger once.

```ts
keyboard.on({
    keys: ['A', 'B', 'C'],
    callback: () => doSomething(),
    type: 'press'
});
```

This example will trigger the callback when you hold the key. If you press the key and release it immediately it won't trigger anything.

```ts
keyboard.on({
    keys: ['A', 'B', 'C'],
    callback: () => doSomething(),
    type: 'hold'
});
```

This example will trigger the callback when you lift your finger from the key. The callback will only trigger when you release the keys.

```ts
keyboard.on({
    keys: ['A'],
    callback: () => doSomething(),
    type: 'lift'
});
```

:::caution
You can only have a single key to trigger an action on `lift`. Using multiple keys will result in an error.
:::

This example will trigger the callback when you press the key and also when you hold it.

```ts
keyboard.on({
    keys: ['A', 'B', 'C'],
    callback: () => doSomething(),
    type: ['press', 'hold']
});
```

### Registering Multiple Callbacks :badge[2.4.4]{variant="note"}

You can now register multiple callbacks or actions for the same key combination and type. All callbacks will be executed in the order they were registered.

```ts
// Register first callback
keyboard.on({
    keys: ['A'],
    callback: () => console.log('First callback'),
    type: 'press'
});

// Register second callback for the same key combination
keyboard.on({
    keys: ['A'],
    callback: () => console.log('Second callback'),
    type: 'press'
});

// When 'A' is pressed, both callbacks will execute:
// Output: 'First callback'
// Output: 'Second callback'
```

This is particularly useful when different parts of your application need to respond to the same keyboard input without having to manually manage callback registration and unregistration.

:::caution
Attempting to register the exact same callback reference or action twice will result in an error to prevent accidental duplicates.
:::

## .off(keys, callback)

Removes an already set up key combination or a specific callback from a key combination. If there are no more registered key combinations, the event listeners will be automatically removed.

```ts
keyboard.off(keys: (string | number)[], callback?: string | Function)
```

### keys

The keys array is an array of the keys involved in a key combination that you want to remove.

### callback (optional)

The specific callback function or action name you want to remove from the key combination. If not provided, all callbacks for the key combination will be removed.

### Removing All Callbacks

If you provide only the keys array, all callbacks registered for that key combination will be removed across all types (press, hold, lift).

```ts
// Remove all callbacks for this key combination
keyboard.off(['A', 'B', 'C'])
```

If you have added the key combination as keycodes or using the KEYS global object you need to remove them the same way:

```ts
keyboard.off([65, 66, 67])
```

```ts
keyboard.off([KEYS.A, KEYS.B, KEYS.C])
```

### Removing a Specific Callback

To remove only a specific callback while keeping others, pass the callback as the second parameter:

```ts
const myCallback = () => console.log('My callback');

keyboard.on({
    keys: ['A'],
    callback: myCallback,
    type: 'press'
});

// Later, remove only this specific callback
keyboard.off(['A'], myCallback);
```

This is useful when multiple callbacks are registered for the same key combination:

```ts
const callback1 = () => console.log('First');
const callback2 = () => console.log('Second');

keyboard.on({ keys: ['A'], callback: callback1, type: 'press' });
keyboard.on({ keys: ['A'], callback: callback2, type: 'press' });

// Remove only callback1, callback2 will still execute
keyboard.off(['A'], callback1);
```

:::caution
Anonymous arrow functions (`() => {}`) cannot be removed individually since they don't have a reference. To remove specific callbacks, always store them in a variable first, similar to how `removeEventListener` works in the DOM.
:::