Hotkeys Docs
Octane Example: UseHeldKeys
import { createRoot, useEffect, useState } from 'octane'
import {
HotkeysProvider,
formatForDisplay,
useHeldKeyCodes,
useHeldKeys,
} from '@tanstack/octane-hotkeys'
import './index.css'
function App() @{
const heldKeys = useHeldKeys()
const heldCodes = useHeldKeyCodes()
const [history, setHistory] = useState<Array<string>>([])
useEffect(() => {
if (heldKeys.length > 0) {
const combo = heldKeys
.map((k) => formatForDisplay(k, { useSymbols: true }))
.join(' + ')
setHistory((h) => {
// Only add if different from last entry
if (h[h.length - 1] !== combo) {
return [...h.slice(-9), combo]
}
return h
})
}
}, [heldKeys])
<div className="app">
<header>
<h1>useHeldKeys</h1>
<p>
Returns an array of all currently pressed keys. Useful for displaying
key combinations or building custom shortcut recording.
</p>
</header>
<main>
<section className="demo-section">
<h2>Currently Held Keys</h2>
<div className="key-display">
@if (heldKeys.length > 0) { @for (const [index, key] of Array.from(heldKeys.entries()); key key) { const code = heldCodes[key]
<>
@if (index > 0) { <span className="plus">+</span> }
<kbd className="large">
{formatForDisplay(key, { useSymbols: true })}
@if (code && code !== key) { <small className="code-label">{code}</small> }
</kbd>
</> } } @else { <span className="placeholder">Press any keys...</span> }
</div>
<div className="stats">
Keys held: <strong>{heldKeys.length}</strong>
</div>
</section>
<section className="demo-section">
<h2>Usage</h2>
<pre className="code-block">{`import { useHeldKeys } from '@tanstack/octane-hotkeys'
function KeyDisplay() @{
const heldKeys = useHeldKeys()
<div>Currently pressed: {heldKeys.join(' + ') || 'None'}</div>
}`}</pre>
</section>
<section className="demo-section">
<h2>Try These Combinations</h2>
<ul>
<li>
Hold <kbd>Shift</kbd> + <kbd>Control</kbd> + <kbd>A</kbd>
</li>
<li>Press multiple letter keys at once</li>
<li>Hold modifiers and watch them appear</li>
<li>Release keys one by one</li>
</ul>
</section>
<section className="demo-section">
<h2>Recent Combinations</h2>
@if (history.length > 0) { <ul className="history-list">
@for (const [i, combo] of Array.from(history.entries()); key i) {
<li>{combo}</li> }
</ul> } @else { <p className="placeholder">Press some key combinations...</p> }
<button onClick={() => setHistory([])}>Clear History</button>
</section>
<section className="demo-section">
<h2>Use Cases</h2>
<ul>
<li>Building a keyboard shortcut recorder</li>
<li>Displaying currently held keys to users</li>
<li>Debugging keyboard input</li>
<li>Creating key combination tutorials</li>
</ul>
</section>
</main>
</div>
}
function Root() @{
<HotkeysProvider><App /></HotkeysProvider>
}
const root = createRoot(document.getElementById('root')!)
root.render(Root)
import.meta.hot?.dispose(() => root.unmount())