Recipes
Keyboard Shortcuts
Implementing global and contextual keyboard shortcuts.
Implementing global and contextual keyboard shortcuts.
Problem
You want to add keyboard shortcuts for common actions like save, undo, or navigation.
Solution
Use app.keys() for global shortcuts and app.modes() for modal (contextual) keymaps.
Complete Example
import { ui } from "@rezi-ui/core";
import { createNodeApp } from "@rezi-ui/node";
type State = {
content: string;
saved: boolean;
mode: "insert" | "normal";
helpOpen: boolean;
};
const app = createNodeApp<State>({
initialState: { content: "", saved: true, mode: "insert", helpOpen: false },
});
app.view((state) =>
ui.column({ flex: 1, gap: 1, p: 1 }, [
ui.row({ gap: 1, justify: "between" }, [
ui.text(state.saved ? "Saved" : "Modified"),
ui.text(`Mode: ${state.mode}`, { style: { dim: true } }),
ui.text(app.pendingChord ? `Waiting: ${app.pendingChord}` : "Ready", { style: { dim: true } }),
]),
ui.input({
id: "editor",
value: state.content,
onInput: (value) => app.update((s) => ({ ...s, content: value, saved: false })),
}),
ui.row({ gap: 2 }, [
ui.row({ gap: 1 }, [ui.kbd(["Ctrl", "S"]), ui.text("Save")]),
ui.row({ gap: 1 }, [ui.kbd("Esc"), ui.text("Normal mode")]),
ui.row({ gap: 1 }, [ui.kbd("i"), ui.text("Insert mode")]),
ui.row({ gap: 1 }, [ui.kbd("?"), ui.text("Help")]),
ui.row({ gap: 1 }, [ui.kbd("q"), ui.text("Quit")]),
]),
state.helpOpen
? ui.modal({
id: "help",
title: "Shortcuts",
content: ui.keybindingHelp(app.getBindings()),
actions: [ui.button({ id: "help-close", label: "Close", onPress: () => app.update((s) => ({ ...s, helpOpen: false })) })],
onClose: () => app.update((s) => ({ ...s, helpOpen: false })),
})
: null,
])
);
// Global shortcuts
app.keys({
"ctrl+s": {
handler: (ctx) => ctx.update((s) => ({ ...s, saved: true })),
description: "Save",
},
"?": {
handler: (ctx) => ctx.update((s) => ({ ...s, helpOpen: true })),
description: "Show shortcuts",
},
"ctrl+q": {
handler: () => app.stop(),
description: "Force quit",
},
q: {
handler: (ctx) => {
if (ctx.state.mode === "normal") app.stop();
},
description: "Quit (normal mode)",
},
});
// Modal (contextual) keymaps
app.modes({
insert: {
escape: {
handler: (ctx) => ctx.update((s) => ({ ...s, mode: "normal" })),
description: "Enter normal mode",
},
},
normal: {
i: {
handler: (ctx) => ctx.update((s) => ({ ...s, mode: "insert" })),
description: "Enter insert mode",
},
},
});
app.setMode("insert");
await app.start();Explanation
app.keys()registers global bindings (available in all modes).app.modes()registers per-mode bindings (Vim-style “normal/insert”).descriptionmetadata enables auto-generated help views viaapp.getBindings().app.pendingChordexposes in-progress chord prefixes for status feedback.- Use
ui.kbd(...)to display shortcuts directly in your UI.
Overlay item shortcuts
shortcut on dropdown and command-palette items is currently a display/filter hint.
- In dropdowns,
routeDropdownKey(...)handles navigation keys (Up,Down,Enter,Space,Escape) but does not execute arbitrary shortcut combos. - In command palette, shortcut text is displayed and participates in search matching, but shortcut combos are not auto-bound.
- Register actual key combos with
app.keys()(orapp.modes()) and call the same action handlers your overlay uses.
Related
- Kbd - Displaying keyboard shortcuts