Sent 0 times, 0 drafts started. Press the keys shown on the buttons.
import * as React from "react"
import { Plus, Send } from "lucide-react"
When to use it#
Use a hotkey for actions that people repeat all day: save, send, create, search, move between rows. A shortcut saves a trip to the mouse, and showing it on the button teaches it.
A shortcut should never be the only way to do something. People on a phone, or who cannot use a keyboard, need the button as well. Keep to a few, and use combinations with Mod, because a plain letter competes with typing.
The hotkey string#
A hotkey is the modifiers and one key, joined with +: "Mod+S", "Mod+Shift+K", "Alt+N", "Escape". It ignores case and spaces. The same string is shown to people and bound to the key, so the two cannot drift apart.
Mod is the main modifier of the system: Cmd on a Mac, Ctrl everywhere else. Use it for most shortcuts, so one string works on every platform.
| Part | What you can write |
|---|---|
| Modifiers | Mod, Ctrl (Control), Alt (Option), Shift, Meta (Cmd) |
| Letters and digits | a to z, 0 to 9 |
| Named keys | Enter, Escape, Space, Tab, Backspace, Delete, the four arrow keys, Home, End, PageUp, PageDown, F1 to F12 |
| Punctuation | , . / ; ' [ ] - = \ and the backtick |
The key + itself and sequences such as "g then h" are not supported. An invalid string binds nothing and is shown as typed, so a mistake is easy to see.
| Hotkey | Mac | Windows and Linux |
|---|---|---|
Mod+K | ⌘ K | Ctrl + K |
Mod+Shift+K | ⇧⌘ K | Ctrl + Shift + K |
Mod+Enter | ⌘ ↵ | Ctrl + Enter |
Escape | Esc | Esc |
Import#
import {
useHotkey,
useHotkeyLabel,
useHotkeyTrigger,
formatHotkey,
parseHotkey,
} from "@hel/ui/hotkeys"On components#
Give a component a hotkey, and it shows the hint and handles the key. Pressing the key clicks the element, as if someone had clicked it. The onClick you already have is the action, so there is no second function to wire.
<Button hotkey="Mod+S" onClick={save}>Save</Button>
<DropdownMenuItem hotkey="Mod+D" onClick={duplicate}>Duplicate</DropdownMenuItem>A disabled element does nothing, an element that is not on the page does nothing, and a menu item closes its menu, just like a click. A plain key or a Shift or Alt combination does not fire while someone types in a field, but a Mod combination does, so Mod+Enter can send from inside a text box. Holding the key does not repeat the action.
These components take hotkey: Button, SidebarMenuButton, DropdownMenuItem and ContextMenuItem, and the command and menubar items built on them. The sidebar toggle (shortcut, "b" by default) and the command palette (shortcut, "k" by default) use the same system.
Examples#
Buttons#
The shortcut works from anywhere on the page, for as long as the button is on it. In the preview at the top of this page, press Ctrl and Enter, or Alt and N, and watch the counters.
Your own actions#
useHotkey(hotkey, handler, options) runs a function when the key is pressed. It needs no list of dependencies, because the latest handler is always used. Turn it off without removing it with enabled, which suits a key that only makes sense while something is open.
Quantity: 0
Alt + ↑Alt + ↓import * as React from "react"
import { Button } from "@hel/ui/button"| Option | Default | What it does |
|---|---|---|
enabled | true | Turns the binding off. |
preventDefault | true | Stops the browser's own action, such as saving the page on Mod+S. |
allowInInputs | only with Mod, Ctrl or Meta | Lets the key fire while a text field has focus. |
allowRepeat | false | Lets holding the key repeat the action. |
Pass undefined as the hotkey and the hook does nothing, so it can stay in your code unconditionally. To show a hint without binding anything, use Kbd with hotkey.
Menus#
A menu removes its items from the page when it closes, so the hotkey of an item works only while the menu is open, like the shortcuts in a desktop application. Open this one, then press the keys shown.
Last action: Nothing yet
import * as React from "react"
import { Copy, Trash2 } from "lucide-react"
If a shortcut must also work when the menu is closed, bind it where the action lives with useHotkey, and show the same text on the item with kbd.
useHotkey("Mod+D", duplicate)
<DropdownMenuItem kbd={formatHotkey("Mod+D")} onClick={duplicate}>
Duplicate
</DropdownMenuItem>Prefer Mod combinations on menu items, because a single letter competes with typing to jump to an item.
Good to know#
- Two bindings on the same key both fire, and in development a one-time warning in the console says so.
Mod+KandCtrl+Kcount as the same key on Windows. - Keys pressed while an input method (IME) is composing text are ignored.
- The first render on the client matches the server, because the platform is treated as "other" until the page has loaded, and the labels then switch to ⌘ on a Mac.
- To hide every shortcut hint in an app, set
shortcuts.visibletofalsein the config. The keys still work.
Props#
Components with a hotkey#
| Prop | Type | Default |
|---|---|---|
hotkey | a hotkey string | none |
kbd | string | the label of hotkey |
kbd only shows text and binds nothing. If both are given, kbd is the text shown.
Functions#
| Function | Use |
|---|---|
useHotkey(hotkey, handler, options?) | Runs a function when the key is pressed. |
useHotkeyLabel(hotkey) | The text to show for the platform, or undefined for no hotkey. |
useHotkeyTrigger(hotkey, { enabled, ref }) | Binds a key to an element, and returns the ref to put on it. |
formatHotkey(hotkey, platform?) | The label as plain text. Works on a server. |
parseHotkey(hotkey) | The parts of a hotkey. Works on a server. |