Keybinds
The Keybinds
component is an easy way to set up keyboard + mouse binding logic in your UI.
It works together with the Keybind
component, which represents a single action slot. Keybinds
provides context, conflict handling, and programmatic control.
Wrap all your Keybind
items in a Keybinds
component. Each Keybind
needs an action
and can optionally get an initial value
.
import Keybinds from '@components/Basic/Keybinds/Keybinds';import Keybind from '@components/Basic/Keybinds/Keybind';
const App = () => { return ( <Keybinds> <Keybind action="forward" value="W" /> <Keybind action="backward" value="S" /> <Keybind action="left" value="A" /> <Keybind action="right" value="D" /> <Keybind action="jump" /> </Keybinds> );};
export default App;
Dynamic Keybinds
Section titled “Dynamic Keybinds”Another way to do it is to map over an array of objects and create a Keybind
for each one:
const mappings = [ { action: "forward", value: "W" }, { action: "backward", value: "S" }, { action: "left", value: "A" }, { action: "right", value: "D" }, { action: "jump", value: null }];
<Keybinds> <For each={mappings}> {(mapping) => <Keybind action={mapping.action} value={mapping.value} />} </For></Keybinds>
With defaults
Section titled “With defaults”You can also provide an initial bindings map to the Keybinds
component via the defaults
prop. This is useful if you want to load presets.
const mappings = { forward: "W", backward: "S", left: "A", right: "D", jump: null};
<Keybinds defaults={mappings}> <For each={Object.keys(mappings)}> {(action) => <Keybind action={action} />} </For></Keybinds>
Prop name | Type | Default | Description |
---|---|---|---|
defaults | Record<string, string | null> | undefined | Initial bindings map: { action: label } . If omitted, children can seed themselves via their value . |
placeholder | string | undefined | Text shown in each Keybind when no key is bound. |
listeningText | string | Press any key... | Text to show while waiting for input. |
overrides | Partial<Record<BindingCode, string>> | {} | Object of custom key overrides. Include only the codes you want to change (e.g., KeyW , ArrowLeft , Digit1 ). See Mappings |
conflictPolicy | 'block' | 'replace-existing' | 'swap' | 'allow-duplicates' | 'allow-duplicates' | How to resolve when a new binding collides with an existing one (see below). |
ref | (ref: KeybindsRef) => void | undefined | Exposes programmatic methods and the current bindings. |
onConflict | (action: string, key: string | null, conflictAction: string) => void | undefined | Called when a conflict happens under any policy. |
onChange | (prev: string | null, next: string | null, action: string) => void | undefined | Called when a bind or unbind operation succeeds. |
Ref API
Section titled “Ref API”To interact with the Keybinds
programmatically, you can use the KeybindsRef
interface. This interface provides properties and methods to access and manipulate the component’s state.
Properties
Section titled “Properties”Property | Type | Description |
---|---|---|
bindings | Record<string, string | null> | The current state of the bindings map. Use to retrieve the up-to-date bindings object. |
Methods
Section titled “Methods”Method | Parameters | Return Value | Description |
---|---|---|---|
bind | (action: string, newKey: string | null) | void | Programmatically bind an action. Applies the current conflictPolicy . |
unbindKey | (key: string | null) | void | Unbinds all actions that currently use this key (no-op if null ). |
mapBindings | (bindings: Record<string, string | null>) | void | Bulk-apply bindings (clears existing, then binds each). Conflict policy still applies per entry. |
clearAll | () | void | Clears all keys by setting every action’s value to null . |
reset | () | void | Restores to the original baseline captured on mount: defaults if provided, otherwise whatever the children had seeded initially. |
Conflict policies
Section titled “Conflict policies”When a user tries to bind a key that is already in use, one of the following policies will be applied:
block
: The new binding is rejected, and the existing one remains unchanged. It displays a console warn.replace-existing
: The new binding replaces the existing one, unbinding the previous action.swap
: The new binding takes the place of the existing one, and the existing action is assigned to the key that was previously bound to the new action.allow-duplicates
: Both actions are allowed to share the same key.
All policies will trigger the onConflict
callback if provided to the component.
Keybind
Section titled “Keybind”The Keybind
component represents a single action slot. It must be a child of the Keybinds
component. When clicked,
it starts to listen for the user to press a key or mouse button to bind the associated action.
Prop name | Type | Default | Description |
---|---|---|---|
action | string | undefined | The action that will have a key bound to it. |
value | string | undefined | undefined | The value associated with the keybind by default. If omitted, it will be null. The string provided must match the label from the mappings object, unless overridden. |
Retrieving current bindings object
Section titled “Retrieving current bindings object”When users change keybinds, you will likely want to save the new bindings map somewhere.
You can do this by accessing the bindings
property.
When accessed it will return the up to date object with the currently set bindings.
To achieve this, you need to use a ref:
- Create a ref variable with the type
KeybindsRef
. - Pass the ref variable to the
Keybinds
component via theref
prop. - Access the
bindings
property on the ref variable whenever you need to retrieve the current bindings object. - Optionally, you can use the
onChange
callback to be notified whenever a user successfully changes a binding.
import Keybinds, { KeybindsRef } from '@components/Basic/Keybinds/Keybinds';import Keybind from '@components/Basic/Keybinds/Keybind';
const App = () => { let keybindsRef!: KeybindsRef;
const retrieveBindings = (prev: string | null, next: string | null, action: string) => { console.log(`Changed "${action}" from "${prev}" to "${next}"`); console.log(keybindsRef.bindings); }
return ( <Keybinds ref={keybindsRef} onChange={retrieveBindings} conflictPolicy="block"> <Keybind action={'forward'} value="W" /> <Keybind action={'backward'} value="Down" /> </Keybinds> );};
export default App;
Reset to defaults
Section titled “Reset to defaults”You can reset all keybinds to their original state by calling the reset
method on the ref.
This will restore the internal state to the initial defaults
if provided, otherwise whatever the children had seeded initially when first rendered.
To achieve this, you need to use a ref:
- Create a ref variable with the type
KeybindsRef
. - Pass the ref variable to the
Keybinds
component via theref
prop. - Reset the keybinds by calling the
reset
method on the ref variable whenever needed.
import Keybinds, { KeybindsRef } from '@components/Basic/Keybinds/Keybinds';import Keybind from '@components/Basic/Keybinds/Keybind';
const App = () => { let keybindsRef!: KeybindsRef;
const resetToDefaults = () => keybindsRef.reset();
return ( <Keybinds ref={keybindsRef} > <Keybind action={'forward'} value="W" /> <Keybind action={'backward'} value="Down" /> </Keybinds> );};
export default App;
In this case because no defaults
prop was provided, it will reset to the original values seeded by the children: forward: "W"
and backward: "Down"
.
Programmatically binding/unbinding keys
Section titled “Programmatically binding/unbinding keys”You can programmatically bind or unbind keys by using the bind
and unbindKey
methods on the ref.
To achieve this, you need to use a ref:
- Create a ref variable with the type
KeybindsRef
. - Pass the ref variable to the
Keybinds
component via theref
prop. - Rebind a key to an action by calling the
bind
method on the ref variable, passing the action and the new key as arguments. - Unbind a key from all actions by calling the
unbindKey
method on the ref variable, passing the key to unbind as an argument.
import Keybinds, { KeybindsRef } from '@components/Basic/Keybinds/Keybinds';import Keybind from '@components/Basic/Keybinds/Keybind';
const App = () => { let keybindsRef!: KeybindsRef;
const rebindForward = () => keybindsRef.bind('forward', 'Up'); const unbindBackward = () => keybindsRef.unbindKey('Down');
return ( <> <button onClick={rebindForward}>Rebind Forward to Up</button> <button onClick={unbindBackward}>Unbind backward</button> <Keybinds ref={keybindsRef} conflictPolicy="block" placeholder="Unbound"> <Keybind action={'forward'} value="W" /> <Keybind action={'backward'} value="Down" /> </Keybinds> </> );};
export default App;
If operations are successful, the onChange
callback will be triggered if provided.
Triggering a function when conflicts happen
Section titled “Triggering a function when conflicts happen”You can be notified when a conflict happens by providing the onConflict
callback to the Keybinds
component.
This can be useful if you want to display a message to the user or prompt them for an action. The onConflict
callback will return the following parameters:
action
: The action that the user is trying to bind.key
: The key that the user is trying to bind.conflictAction
: The action that is currently bound to the key.
To achieve this, you need to provide a function to the onConflict
prop of the Keybinds
component.
import Keybinds from '@components/Basic/Keybinds/Keybinds';import Keybind from '@components/Basic/Keybinds/Keybind';
const App = () => { let keybindsRef!: KeybindsRef;
const handleConflict = (action: string, key: string | null, conflictAction: string) => { console.log(`Conflict detected! Tried to bind "${key}" to "${action}", but it's already bound to "${conflictAction}".`); }
return ( <> <Keybinds conflictPolicy="block" onConflict={handleConflict}> <Keybind action={'forward'} value="W" /> <Keybind action={'backward'} value="Down" /> </Keybinds> </> );};
export default App;
Applying presets
Section titled “Applying presets”You can apply a preset bindings map by using the mapBindings
method on the ref. This is useful if you want to allow users to switch between different keybind presets.
To achieve this, you need to use a ref:
- Create a ref variable with the type
KeybindsRef
. - Pass the ref variable to the
Keybinds
component via theref
prop. - Apply a new bindings map by calling the
mapBindings
method on the ref variable, passing the new bindings object as an argument.
import Keybinds, { KeybindsRef } from '@components/Basic/Keybinds/Keybinds';import Keybind from '@components/Basic/Keybinds/Keybind';
const App = () => { let keybindsRef!: KeybindsRef;
const preset = { forward: "Up", backward: "Down", left: "Left", right: "Right", jump: null };
const changePreset = () => keybindsRef.mapBindings(preset);
return ( <> <button onClick={changePreset}>Change preset</button> <Keybinds ref={keybindsRef} conflictPolicy="block" placeholder="Unbound"> <Keybind action={'forward'} value="W" /> <Keybind action={'backward'} value="S" /> <Keybind action={'left'} value="A" /> <Keybind action={'right'} value="D" /> <Keybind action={'jump'} value="Space" /> </Keybinds> </> );};
export default App;
You can see an extended example of presets in the Menu UI view located at src/views/menu/Menu.tsx
.
Key label overrides (custom key display)
Section titled “Key label overrides (custom key display)”In order to provide custom values for some keys you need to customize how keys are displayed. To achieve that, do the following.
- Create an object where the keys are the codes you want to override and the values are the custom labels you want to display.
- Pass the object to the
overrides
prop of theKeybinds
component. - Now the
Keybinds
component will consider you custom labels as valid display values.
import Keybinds, { KeybindsRef } from '@components/Basic/Keybinds/Keybinds';import Keybind from '@components/Basic/Keybinds/Keybind';
const App = () => { const overrides = { "ArrowUp": "Up", "ArrowDown": "Down", "Backquote": "`", "BracketLeft": "[", "BracketRight": "]", "0": "Mouse Left", "2": "Mouse Right", "WheelUp": "Wheel Up", };
return ( <> <Keybinds overrides={overrides} conflictPolicy="block" placeholder="Unbound"> <Keybind action={'forward'} value="Up" /> <Keybind action={'backward'} value="Down" /> <Keybind action={'special-action-one'} value="`" /> <Keybind action={'special-action-two'} value="[" /> <Keybind action={'special-action-three'} value="]" /> <Keybind action={'select-item'} value="Mouse Left" /> <Keybind action={'interact'} value="Mouse Right" /> <Keybind action={'view-up'} value="Wheel up" /> </Keybinds> </> );};
export default App;
Reference
Section titled “Reference”Mappings object
Section titled “Mappings object”The Keybinds
component comes with a default mapping object that translates common KeyboardEvent.code
and mouse button codes to user-friendly labels.
The mappings object uses KeyboardEvent.code for keyboard mappings and MouseEvent.button for mouse button mappings.
The object is located at src/components/Basic/Keybinds/mappings.ts
.
Keyboard
Section titled “Keyboard”Code | Label |
---|---|
KeyA | A |
KeyB | B |
KeyC | C |
KeyD | D |
KeyE | E |
KeyF | F |
KeyG | G |
KeyH | H |
KeyI | I |
KeyJ | J |
KeyK | K |
KeyL | L |
KeyM | M |
KeyN | N |
KeyO | O |
KeyP | P |
KeyQ | Q |
KeyR | R |
KeyS | S |
KeyT | T |
KeyU | U |
KeyV | V |
KeyW | W |
KeyX | X |
KeyY | Y |
KeyZ | Z |
Digit0 | 0 |
Digit1 | 1 |
Digit2 | 2 |
Digit3 | 3 |
Digit4 | 4 |
Digit5 | 5 |
Digit6 | 6 |
Digit7 | 7 |
Digit8 | 8 |
Digit9 | 9 |
F1 | F1 |
F2 | F2 |
F3 | F3 |
F4 | F4 |
F5 | F5 |
F6 | F6 |
F7 | F7 |
F8 | F8 |
F9 | F9 |
F10 | F10 |
F11 | F11 |
F12 | F12 |
F13 | F13 |
F14 | F14 |
F15 | F15 |
F16 | F16 |
F17 | F17 |
F18 | F18 |
F19 | F19 |
F20 | F20 |
F21 | F21 |
F22 | F22 |
F23 | F23 |
F24 | F24 |
Numpad0 | Num 0 |
Numpad1 | Num 1 |
Numpad2 | Num 2 |
Numpad3 | Num 3 |
Numpad4 | Num 4 |
Numpad5 | Num 5 |
Numpad6 | Num 6 |
Numpad7 | Num 7 |
Numpad8 | Num 8 |
Numpad9 | Num 9 |
NumpadAdd | + |
NumpadSubtract | - |
NumpadMultiply | * |
NumpadDivide | / |
NumpadDecimal | . |
NumpadComma | , |
NumpadEnter | Num Enter |
NumpadEqual | Num = |
Backquote | ` |
Minus | - |
Equal | = |
BracketLeft | [ |
BracketRight | ] |
Backslash | \ |
Semicolon | ; |
Quote | ’ |
Comma | , |
Period | . |
Slash | / |
ShiftLeft | L Shift |
ShiftRight | R Shift |
ControlLeft | L Ctrl |
ControlRight | R Ctrl |
AltLeft | L Alt |
AltRight | R Alt |
MetaLeft | L Meta |
MetaRight | R Meta |
Escape | Esc |
Tab | Tab |
CapsLock | Caps |
Space | Space |
Enter | Enter |
Backspace | Back |
Delete | Del |
Insert | Ins |
Home | Home |
End | End |
PageUp | PgUp |
PageDown | PgDn |
ArrowUp | Up |
ArrowDown | Down |
ArrowLeft | Left |
ArrowRight | Right |
PrintScreen | PrtSc |
ScrollLock | Scroll |
Pause | Pause |
ContextMenu | Menu |
NumLock | NumLock |
AudioVolumeMute | Mute |
AudioVolumeDown | Vol- |
AudioVolumeUp | Vol+ |
MediaTrackNext | Next |
MediaTrackPrevious | Prev |
MediaStop | Stop |
MediaPlayPause | Play/Pause |
BrowserBack | BrowserBack |
BrowserForward | BrowserForward |
BrowserRefresh | BrowserRefresh |
BrowserStop | BrowserStop |
BrowserSearch | BrowserSearch |
BrowserFavorites | BrowserFav |
BrowserHome | BrowserHome |
Mouse Buttons
Section titled “Mouse Buttons”Code | Label |
---|---|
0 | LMB |
1 | MMB |
2 | RMB |
3 | BMB |
4 | FMB |
Mouse Wheel
Section titled “Mouse Wheel”Code | Label |
---|---|
WheelUp | Wheel Up |
WheelDown | Wheel Down |