use-hotkeys

Listen for keys combinations on document element

Import

Usage

use-hotkeys accepts as its first argument an array of hotkeys and handler tuples:

  • hotkey - hotkey string, for example ctrl+E, shift+alt+L, mod+S
  • handler - event handler called when a given combination was pressed
  • options - object with extra options for hotkey handler
import { useHotkeys } from '@mantine/hooks';

function Demo() {
  // ctrl + J and ⌘ + J to toggle color scheme
  // ctrl + K and ⌘ + K to search
  useHotkeys([
    ['mod+J', () => console.log('Toggle color scheme')],
    ['ctrl+K', () => console.log('Trigger search')],
    ['alt+mod+shift+X', () => console.log('Rick roll')],
  ]);

  return null;
}

The second argument is a list of HTML tags on which hotkeys should be ignored. By default, hotkeys events are ignored if the focus is in input, textarea and select elements.

import { useHotkeys } from '@mantine/hooks';

function Demo() {
  // Ignore hotkeys events only when focus is in input and textarea elements
  useHotkeys(
    [['ctrl+K', () => console.log('Trigger search')]],
    ['INPUT', 'TEXTAREA']
  );

  // Empty array – do not ignore hotkeys events on any element
  useHotkeys([['ctrl+K', () => console.log('Trigger search')]], []);
}

Targeting elements

use-hotkeys hook can work only with document element, you will need to create your own event listener if you need to support other elements. For this purpose, @mantine/hooks package exports getHotkeyHandler function which should be used with onKeyDown:

import { useState } from 'react';
import { getHotkeyHandler } from '@mantine/hooks';
import { notifications } from '@mantine/notifications';
import { TextInput } from '@mantine/core';

function Demo() {
  const [value, setValue] = useState("I've just used a hotkey to send a message");
  const handleSubmit = () => notifications.show({ title: 'Your message', message: value });
  const handleSave = () => notifications.show({ title: 'You saved', color: 'teal', message: value });

  return (
    <TextInput
      placeholder="Your message"
      label="Press ⌘+Enter or Ctrl+Enter when input has focus to send message"
      value={value}
      onChange={(event) => setValue(event.target.value)}
      onKeyDown={getHotkeyHandler([
        ['mod+Enter', handleSubmit],
        ['mod+S', handleSave],
      ])}
    />
  );
}

With getHotkeyHandler you can also add events to any dom node using .addEventListener:

import { getHotkeyHandler } from '@mantine/hooks';

document.body.addEventListener(
  'keydown',
  getHotkeyHandler([
    ['mod+Enter', () => console.log('Submit')],
    ['mod+S', () => console.log('Save')],
  ])
);

Supported formats

  • mod+S – detects ⌘+S on macOS and Ctrl+S on Windows
  • ctrl+shift+X – handles multiple modifiers
  • alt + shift + L – you can use whitespace inside hotkey
  • ArrowLeft – you can use special keys using this format

Types

@mantine/hooks exports HotkeyItemOptions and HotkeyItem types:

interface HotkeyItemOptions {
  preventDefault?: boolean;
}

type HotkeyItem = [
  string,
  (event: KeyboardEvent) => void,
  HotkeyItemOptions?,
];

HotkeyItem type can be used to create hotkey items outside of use-hotkeys hook:

import { HotkeyItem, useHotkeys } from '@mantine/hooks';

const hotkeys: HotkeyItem[] = [
  [
    'mod+J',
    () => console.log('Toggle color scheme'),
    { preventDefault: false },
  ],
  ['ctrl+K', () => console.log('Trigger search')],
  ['alt+mod+shift+X', () => console.log('Rick roll')],
];

useHotkeys(hotkeys);

Definition

function useHotkeys(
  hotkeys: HotkeyItem[],
  tagsToIgnore?: string[],
  triggerOnContentEditable?: boolean
): void;