Skip to main content

Overview

HotkeysProvider is a React context provider that enables advanced hotkey management features like scoping, dynamic scope toggling, and access to all registered hotkeys in your application. It wraps your application (or part of it) and provides context to all child components.
The HotkeysProvider is optional. You can use useHotkeys without it, but you won’t have access to scope management features or be able to retrieve the list of registered hotkeys.

Signature

function HotkeysProvider({ 
  initiallyActiveScopes, 
  children 
}: Props): JSX.Element

Props

initiallyActiveScopes
string[]
default:["*"]
An array of scope names that should be active when the provider mounts. By default, the wildcard scope '*' is active, which means all hotkeys without an explicit scope will be active.You can initialize with multiple scopes or specific scopes to control which hotkeys are active on mount.
children
ReactNode
required
The React components that should have access to the hotkeys context. All useHotkeys hooks within these components will be able to use scopes and will be registered in the global hotkeys list.

Context API

The HotkeysProvider exposes the following context values via the useHotkeysContext hook:
hotkeys
ReadonlyArray<Hotkey>
A read-only array of all currently registered hotkeys in the application. Each hotkey object contains information about the key combination, scopes, description, and metadata.
activeScopes
string[]
An array of currently active scope names. Hotkeys are only triggered if they belong to one of the active scopes or the wildcard scope '*'.
toggleScope
(scope: string) => void
Toggle a scope on or off. If the scope is currently active, it will be disabled. If it’s inactive, it will be enabled. When toggling from the wildcard scope '*', it will replace it with the specified scope.
enableScope
(scope: string) => void
Enable a specific scope, adding it to the list of active scopes. If the wildcard scope '*' is currently active, it will be replaced with the specified scope.
disableScope
(scope: string) => void
Disable a specific scope, removing it from the list of active scopes. Hotkeys in this scope will no longer trigger.

Usage

Basic Setup

Wrap your application with the HotkeysProvider:
import { HotkeysProvider } from 'react-hotkeys-hook'

function App() {
  return (
    <HotkeysProvider>
      <YourApplication />
    </HotkeysProvider>
  )
}

Custom Initial Scopes

Start with specific scopes active instead of the default wildcard:
import { HotkeysProvider } from 'react-hotkeys-hook'

function App() {
  return (
    <HotkeysProvider initiallyActiveScopes={['editor', 'global']}>
      <YourApplication />
    </HotkeysProvider>
  )
}

Managing Scopes

Use the context API to dynamically control which hotkeys are active:
import { HotkeysProvider, useHotkeysContext, useHotkeys } from 'react-hotkeys-hook'

function Editor() {
  const { activeScopes, enableScope, disableScope, toggleScope } = useHotkeysContext()

  // Register scoped hotkeys
  useHotkeys('ctrl+s', () => console.log('Save'), { scopes: 'editor' })
  useHotkeys('ctrl+o', () => console.log('Open'), { scopes: 'editor' })
  useHotkeys('ctrl+p', () => console.log('Print'), { scopes: 'preview' })

  return (
    <div>
      <p>Active scopes: {activeScopes.join(', ')}</p>
      
      <button onClick={() => enableScope('editor')}>
        Enable Editor Mode
      </button>
      
      <button onClick={() => enableScope('preview')}>
        Enable Preview Mode
      </button>
      
      <button onClick={() => toggleScope('editor')}>
        Toggle Editor Mode
      </button>
    </div>
  )
}

function App() {
  return (
    <HotkeysProvider initiallyActiveScopes={['global']}>
      <Editor />
    </HotkeysProvider>
  )
}

Accessing Registered Hotkeys

Retrieve all registered hotkeys to display help documentation or keyboard shortcuts:
import { HotkeysProvider, useHotkeysContext, useHotkeys } from 'react-hotkeys-hook'

function KeyboardShortcutsHelp() {
  const { hotkeys } = useHotkeysContext()

  return (
    <div>
      <h2>Keyboard Shortcuts</h2>
      <ul>
        {hotkeys.map((hotkey, index) => (
          <li key={index}>
            <kbd>{hotkey.hotkey}</kbd>
            {hotkey.description && ` - ${hotkey.description}`}
            {hotkey.scopes && ` (${hotkey.scopes})`}
          </li>
        ))}
      </ul>
    </div>
  )
}

function App() {
  useHotkeys('ctrl+s', () => console.log('Save'), { 
    description: 'Save document' 
  })
  useHotkeys('ctrl+o', () => console.log('Open'), { 
    description: 'Open file' 
  })
  useHotkeys('ctrl+n', () => console.log('New'), { 
    description: 'Create new document' 
  })

  return (
    <HotkeysProvider>
      <KeyboardShortcutsHelp />
    </HotkeysProvider>
  )
}

Multi-Modal Application

Create an application with different modes that have different hotkeys:
import { HotkeysProvider, useHotkeysContext, useHotkeys } from 'react-hotkeys-hook'
import { useState } from 'react'

function ModalEditor() {
  const [mode, setMode] = useState<'normal' | 'insert'>('normal')
  const { enableScope, disableScope } = useHotkeysContext()

  // Normal mode hotkeys
  useHotkeys('i', () => {
    setMode('insert')
    disableScope('normal')
    enableScope('insert')
  }, { scopes: 'normal', description: 'Enter insert mode' })

  useHotkeys('d,d', () => {
    console.log('Delete line')
  }, { scopes: 'normal', description: 'Delete line' })

  // Insert mode hotkeys
  useHotkeys('escape', () => {
    setMode('normal')
    disableScope('insert')
    enableScope('normal')
  }, { scopes: 'insert', description: 'Exit insert mode' })

  return (
    <div>
      <p>Current mode: {mode}</p>
      <textarea placeholder="Type here..." />
    </div>
  )
}

function App() {
  return (
    <HotkeysProvider initiallyActiveScopes={['normal', 'global']}>
      <ModalEditor />
    </HotkeysProvider>
  )
}

Scope Management with Multiple Components

Coordinate hotkeys across different parts of your application:
import { HotkeysProvider, useHotkeysContext, useHotkeys } from 'react-hotkeys-hook'

function Sidebar() {
  const { activeScopes } = useHotkeysContext()
  
  useHotkeys('ctrl+b', () => console.log('Toggle sidebar'), { 
    scopes: 'sidebar',
    description: 'Toggle sidebar visibility'
  })

  return (
    <aside>
      <p>Sidebar hotkeys: {activeScopes.includes('sidebar') ? 'Active' : 'Inactive'}</p>
    </aside>
  )
}

function MainContent() {
  useHotkeys('ctrl+e', () => console.log('Focus editor'), { 
    scopes: 'editor',
    description: 'Focus main editor'
  })

  return <main>Main content</main>
}

function App() {
  const { toggleScope } = useHotkeysContext()

  return (
    <div>
      <button onClick={() => toggleScope('sidebar')}>
        Toggle Sidebar Hotkeys
      </button>
      <button onClick={() => toggleScope('editor')}>
        Toggle Editor Hotkeys
      </button>
      <Sidebar />
      <MainContent />
    </div>
  )
}

function Root() {
  return (
    <HotkeysProvider initiallyActiveScopes={['sidebar', 'editor', 'global']}>
      <App />
    </HotkeysProvider>
  )
}

Important Notes

The wildcard scope '*' is special. When it’s active, all hotkeys without an explicit scope are active. When you enable a specific scope while '*' is active, the wildcard scope is automatically replaced with your specified scope.
Use the description option when registering hotkeys with useHotkeys to make them more useful when displaying them via the hotkeys array from the context.
Scopes are case-sensitive. 'Editor' and 'editor' are treated as different scopes.
You can have multiple scopes active simultaneously. A hotkey will trigger if ANY of its scopes are in the active scopes list.

Type Definitions

The Hotkey type returned in the hotkeys array has the following structure:
type Hotkey = {
  keys?: readonly string[]
  scopes?: string | readonly string[]
  description?: string
  hotkey: string
  alt?: boolean
  ctrl?: boolean
  meta?: boolean
  shift?: boolean
  mod?: boolean
  useKey?: boolean
  isSequence?: boolean
  metadata?: Record<string, unknown>
}
The HotkeysContextType provided by the context:
type HotkeysContextType = {
  hotkeys: ReadonlyArray<Hotkey>
  activeScopes: string[]
  toggleScope: (scope: string) => void
  enableScope: (scope: string) => void
  disableScope: (scope: string) => void
}

Accessing the Context

To access the context values, use the useHotkeysContext hook:
import { useHotkeysContext } from 'react-hotkeys-hook'

function MyComponent() {
  const { hotkeys, activeScopes, enableScope, disableScope, toggleScope } = useHotkeysContext()
  
  // Use context values...
}

Build docs developers (and LLMs) love