Default Behavior
By default, hotkeys are disabled when focus is inside form elements. This prevents accidental hotkey triggers while the user is typing.
import { useHotkeys } from 'react-hotkeys-hook'
function App() {
// This won't trigger when typing in an input field
useHotkeys('s', () => console.log('S pressed'))
return <input type="text" placeholder="Type here" />
}
Typing “search” in the input won’t trigger the hotkey.
Set enableOnFormTags: true to enable hotkeys on all form elements:
import { useHotkeys } from 'react-hotkeys-hook'
function SearchBar() {
useHotkeys('ctrl+k', handleSearch, {
enableOnFormTags: true,
preventDefault: true,
})
return <input type="text" placeholder="Search..." />
}
Enable hotkeys on only certain form elements:
import { useHotkeys } from 'react-hotkeys-hook'
function Form() {
// Only active in input and textarea, not select
useHotkeys('ctrl+enter', handleSubmit, {
enableOnFormTags: ['input', 'textarea'],
preventDefault: true,
})
return (
<form>
<input type="text" /> {/* ✓ Hotkey works here */}
<textarea /> {/* ✓ Hotkey works here */}
<select> {/* ✗ Hotkey doesn't work here */}
<option>Option 1</option>
</select>
</form>
)
}
The following HTML tags and ARIA roles are recognized:
ARIA Roles
searchbox
slider
spinbutton
menuitem
menuitemcheckbox
menuitemradio
option
radio
textbox
import { useHotkeys } from 'react-hotkeys-hook'
function AccessibleForm() {
useHotkeys('ctrl+s', handleSave, {
enableOnFormTags: [
'input',
'textarea',
'searchbox', // ARIA role
'textbox', // ARIA role
],
})
return (
<div>
<input type="text" />
<div role="searchbox" contentEditable />
<div role="textbox" contentEditable />
</div>
)
}
ContentEditable Elements
For elements with contentEditable, use the enableOnContentEditable option:
import { useHotkeys } from 'react-hotkeys-hook'
function RichTextEditor() {
useHotkeys('ctrl+b', makeBold, {
enableOnContentEditable: true,
preventDefault: true,
})
useHotkeys('ctrl+i', makeItalic, {
enableOnContentEditable: true,
preventDefault: true,
})
return (
<div
contentEditable
style={{ border: '1px solid #ccc', padding: '1rem' }}
>
Type here...
</div>
)
}
Combining Both Options
You can enable hotkeys on both form tags and contentEditable:
import { useHotkeys } from 'react-hotkeys-hook'
function Editor() {
useHotkeys('ctrl+s', handleSave, {
enableOnFormTags: ['input', 'textarea'],
enableOnContentEditable: true,
preventDefault: true,
})
return (
<div>
<input type="text" /> {/* ✓ Works */}
<div contentEditable> {/* ✓ Works */}
Rich text content
</div>
</div>
)
}
Common Use Cases
import { useHotkeys } from 'react-hotkeys-hook'
function CommentBox() {
const [comment, setComment] = useState('')
useHotkeys('ctrl+enter', () => handleSubmit(comment), {
enableOnFormTags: ['textarea'],
preventDefault: true,
}, [comment])
return (
<form onSubmit={handleSubmit}>
<textarea
value={comment}
onChange={(e) => setComment(e.target.value)}
placeholder="Write a comment (Ctrl+Enter to submit)"
/>
<button type="submit">Submit</button>
</form>
)
}
Search Bar Navigation
import { useHotkeys } from 'react-hotkeys-hook'
function SearchWithResults() {
const [selectedIndex, setSelectedIndex] = useState(0)
// Navigate results while typing in search
useHotkeys('down', () => setSelectedIndex(i => i + 1), {
enableOnFormTags: ['input'],
preventDefault: true,
})
useHotkeys('up', () => setSelectedIndex(i => Math.max(0, i - 1)), {
enableOnFormTags: ['input'],
preventDefault: true,
})
useHotkeys('enter', () => selectResult(selectedIndex), {
enableOnFormTags: ['input'],
preventDefault: true,
})
return (
<div>
<input type="text" placeholder="Search..." />
<ResultsList selectedIndex={selectedIndex} />
</div>
)
}
Markdown Editor Shortcuts
import { useHotkeys } from 'react-hotkeys-hook'
function MarkdownEditor() {
const textareaRef = useRef<HTMLTextAreaElement>(null)
const wrapSelection = (before: string, after: string) => {
const textarea = textareaRef.current
if (!textarea) return
const start = textarea.selectionStart
const end = textarea.selectionEnd
const text = textarea.value
const selection = text.substring(start, end)
textarea.value =
text.substring(0, start) +
before + selection + after +
text.substring(end)
}
useHotkeys('ctrl+b', () => wrapSelection('**', '**'), {
enableOnFormTags: ['textarea'],
preventDefault: true,
})
useHotkeys('ctrl+i', () => wrapSelection('*', '*'), {
enableOnFormTags: ['textarea'],
preventDefault: true,
})
useHotkeys('ctrl+k', () => wrapSelection('[', '](url)'), {
enableOnFormTags: ['textarea'],
preventDefault: true,
})
return (
<textarea
ref={textareaRef}
placeholder="Write markdown..."
/>
)
}
Autocomplete with Tab
import { useHotkeys } from 'react-hotkeys-hook'
function AutocompleteInput() {
const [value, setValue] = useState('')
const [suggestion, setSuggestion] = useState('')
useHotkeys('tab', () => {
if (suggestion) {
setValue(suggestion)
setSuggestion('')
}
}, {
enableOnFormTags: ['input'],
preventDefault: true,
}, [suggestion])
return (
<div style={{ position: 'relative' }}>
<input
type="text"
value={value}
onChange={(e) => {
setValue(e.target.value)
setSuggestion(getSuggestion(e.target.value))
}}
/>
{suggestion && (
<div style={{ position: 'absolute', color: '#999' }}>
{suggestion}
</div>
)}
</div>
)
}
Excluding Specific Elements
If you enable on form tags but want to exclude specific elements, use the ignoreEventWhen option:
import { useHotkeys } from 'react-hotkeys-hook'
function Form() {
useHotkeys('ctrl+s', handleSave, {
enableOnFormTags: true,
ignoreEventWhen: (event) => {
const target = event.target as HTMLElement
// Ignore if it's a password input
return target.tagName === 'INPUT' &&
(target as HTMLInputElement).type === 'password'
},
})
}
Shadow DOM Support
The library automatically handles custom elements and shadow DOM using composedPath():
import { useHotkeys } from 'react-hotkeys-hook'
function CustomEditor() {
useHotkeys('ctrl+s', handleSave, {
enableOnFormTags: ['input'],
})
return <custom-editor /> {/* Works even in shadow DOM */}
}
The default behavior (hotkeys disabled on form tags) is intentional to prevent conflicts with normal typing. Only enable on form tags when you have specific keyboard shortcuts for input interactions.
Be careful when enabling hotkeys on form tags - you might interfere with native browser shortcuts like Ctrl+A (select all) or Ctrl+C (copy). Use preventDefault carefully.
For rich text editors, enable both enableOnFormTags and enableOnContentEditable to support all editing surfaces.