tinykeys

repository·main·Indexed 26 days ago

https://github.com/jamiebuilds/tinykeys

A tiny (~1KB) modern JavaScript library for managing keyboard shortcuts and sequences. It supports single keys, modifiers, optional modifiers, the $mod alias for platform-agnostic shortcuts, regular expressions, and key sequences. The library provides the tinykeys() function for global registration, createKeybindingsHandler for standalone management, and parseKeybinding for converting keybinding strings into structured formats.

Tokens
2.2K
Snippets
8
Records
11
Agent score
38%

What's inside tinykeys

  1. Use tinykeys for simple keybindings

    main

    To register keybindings globally, import tinykeys and call it with a target element (e.g., window) and a mapping object. The mapping object keys are strings representing the keybinding syntax, and values are the callback functions to execute.

    Supported syntax includes:

    • Single keys (matches event.key or event.code)
    • Modifiers (e.g., Shift+D)
    • Optional modifiers (e.g., [Shift]+D)
    • The $mod alias (Mac: Meta, Windows/Linux: Control)
    • Regular expressions for multiple keys (e.g., $mod+([0-9]))
    • Sequences of presses (e.g., y e e t)
    import { tinykeys } from "tinykeys"
    
    tinykeys(window, {
      "Shift+D": () => {
        alert("The 'Shift' and 'd' keys were pressed at the same time")
      },
      "y e e t": () => {
        alert("The keys 'y', 'e', 'e', and 't' were pressed in order")
      },
      "$mod+([0-9])": event => {
        event.preventDefault()
        alert(`Either 'Control+${event.key}' or 'Meta+${event.key}' were pressed`)
      },
    })
  2. Handle AltGraph (modifier)

    main

    On some non-US layouts (Windows/macOS), the AltGraph key may be reported. To ensure cross-platform compatibility, it is often safer to use event.code (e.g., KeyS) instead of event.key (e.g., S) when dealing with these modifiers.

    tinykeys(window, {
      "Control+Alt+KeyS": event => {
        // macOS: `Control+Alt+S` or `Control+AltGraph+S`
        // Windows: `Control+Alt+S` or `Control+AltGraph+S` or `AltGraph+S`
      },
      "$mod+Alt+KeyS": event => {
        // macOS: `Meta+Alt+S` or `Meta+AltGraph+S`
        // Windows: `Control+Alt+S` or `Control+AltGraph+S` or `AltGraph+S`
      },
    })
  3. Configure tinykeys options

    main

    The third argument to tinykeys is an options object that allows you to customize behavior:

    • event: The keyboard event to listen for. Valid values are "keydown" (default) and "keyup". Do not use "keypress".
    • timeout: The time (in ms) to wait between key presses in a sequence before cancelling. Default is 1000.
    • capture: Boolean to use event capturing.
    • ignore: A filter function to determine which keyboard events should be ignored. By default, tinykeys ignores events from [contenteditable], input, textarea, and select unless they are the event.currentTarget.
    tinykeys(
      window,
      {
        M: toggleMute,
      },
      {
        event: "keyup",
        capture: true,
      },
    )
  4. Use tinykeys in React

    main

    When using tinykeys inside a React component, ensure you return the unsubscribe() function from the useEffect hook to prevent memory leaks and unexpected behavior when the component unmounts.

    import { useEffect } from "react"
    import { tinykeys } from "tinykeys"
    
    function useKeyboardShortcuts() {
      const formatBold = useEffectEvent(() => {
        // ...
      })
    
      const formatItalic = useEffectEvent(() => {
        // ...
      })
    
      useEffect(() => {
        return tinykeys(window, {
          "$mod+b": formatBold,
          "$mod+i": formatItalic,
        })
      }, [])
    }
  5. Create a standalone keybindings handler

    main

    If you prefer to manage the event listener yourself, use createKeybindingsHandler. This returns a function that you can pass to addEventListener.

    import { createKeybindingsHandler } from "tinykeys"
    
    let handler = createKeybindingsHandler({
      "Shift+D": () => {
        alert("The 'Shift' and 'd' keys were pressed at the same time")
      },
      "y e e t": () => {
        alert("The keys 'y', 'e', 'e', and 't' were pressed in order")
      },
      "$mod+KeyD": event => {
        event.preventDefault()
        alert("Either 'Control+d' or 'Meta+d' were pressed")
      },
    })
    
    window.addEventListener("keydown", handler)
  6. Reference common KeyboardEvent keys and codes

    main

    tinykeys matches against KeyboardEvent.key and KeyboardEvent.code. Use the following table for common mappings:

    WindowsmacOSkeycode
    N/ACommand / MetaMetaLeft / MetaRight
    AltOption / AltAltLeft / AltRight
    ControlControl / ^ControlControlLeft / ControlRight
    ShiftShiftShiftShiftLeft / ShiftRight
    SpaceSpaceN/ASpace
    EnterReturnEnterEnter
    EscEscEscapeEscape
    1, 2, etc1, 2, etc1, 2, etcDigit1, Digit2, etc
    a, b, etca, b, etca, b, etcKeyA, KeyB, etc
    ---Minus
    ===Equal
    ===Equal*

    * Note: Some keys share the same code. International layouts may vary.

  7. Use defaultKeybindingsHandlerIgnore to skip form inputs

    main

    The defaultKeybindingsHandlerIgnore function is a predicate that returns true if a keyboard event should be ignored. By default, it ignores:

    • Repeated events (event.repeat)
    • Composition input (event.isComposing)
    • Keyboard events targeting contenteditable elements, input, select, or textarea (unless the target is the currentTarget).

    You can use this to extend the default ignoring logic.

    tinykeys(window, {...}, {
      ignore: event => {
        return (
          // Also ignore events inside a dialog
          event.target.closest("dialog") != null &&
          defaultKeybindingsHandlerIgnore(event)
        );
      }
    })
  8. Register keybindings with tinykeys()

    main

    Use tinykeys to subscribe to keyboard events on a Window or HTMLElement. It accepts a map of keybinding strings to handler functions and returns an unsubscribe function to clean up the event listener.

    Keybinding syntax supports:

    • Single keys: "a"
    • Modifiers: "Shift+d"
    • Optional modifiers: "[Alt]+a"
    • Sequences: "y e e t"
    • Platform-agnostic modifier: "$mod+d" (maps to Control on Windows/Linux and Meta on macOS)
    • Regex: "/(?:a|b)/"
    import { tinykeys } from "tinykeys"
    
    const unsubscribe = tinykeys(window, {
    	"Shift+d": () => {
    		alert("The 'Shift' and 'd' keys were pressed at the same time")
    	},
    	"y e e t": () => {
    		alert("The keys 'y', 'e', 'e', and 't' were pressed in order")
    	},
    	"$mod+d": () => {
    		alert("Either 'Control+d' or 'Meta+d' were pressed")
    	},
    })
    
    // Call unsubscribe() later to stop listening
    // unsubscribe();
  9. Parse keybinding strings with parseKeybinding

    main
    The parseKeybinding function converts a keybinding string into a KeybindingPress array. This is useful if you need to inspect the components of a binding (required modifiers, optional modifiers, and the key/regex).