Skip to content

Keyboard

Every component uses the same vocabulary, so a key means the same thing wherever you meet it. This page is the whole map.

The map

Traversal — moving between components

KeyDoes
TabFocus the next focusable component
Shift+TabFocus the previous one

Traversal belongs to the runtime, not to components. Tab wrapping is per-scope — see Focus, hover, and identity. Apps add their own jumps with focus_key.

Vertical controls — List and an open Select:

KeysMoves the cursor
 j  Ctrl+None item forward
 k  Ctrl+Pone item back
Home / Endto the first / last enabled item
PageDown / PageUpone viewport
Ctrl+D / Ctrl+Uhalf a viewport

Horizontal controls — Tabs:

KeysMoves the cursor
 l  Ctrl+None tab forward
 h  Ctrl+Pone tab back
Home / Endto the first / last enabled tab

Three names for each movement: arrows for everyone, hjkl for vi, and the Ctrl chords readline put in every shell and text field. None of them collide, so a user reaches for whichever they already know.

Disabled items are skipped rather than landed on and stepped over again, and movement clamps at the ends — no wrapping.

Commit and dismiss

KeyDoes
Enter  SpacePress a Button; commit the cursor in List, Select, or Tabs
EscClose a Dialog, a Tooltip, or an open Select panel

Dialog's dismiss key is rebindable with dismiss_key, which takes any KeyChord. Everything else in this table is fixed.

The rules behind the map

Three rules decide whether a component claims a key at all. They matter because they are what keeps your app's own hotkeys working.

A component claims only unmodified keys. Ctrl+S reaches your save handler even while a List has focus. The navigation chords above are the deliberate exception — Ctrl+N is a control's own key, because every control with a cursor wants the same four.

Shift is never navigation. J is not j. Shift is left unclaimed so range-selection can be added later without changing what any key means today.

An unhandled key bubbles. A key a component does not recognise is reported as ignored, and travels up to its ancestors and then to your app. So a single-letter hotkey keeps working while a list has focus — except for the four letters the navigation map takes (h, j, k, l).

That last exception is a real trade. If your app needs j as a global hotkey, bind it outside the focused control, or check it before calling Ratcn::handle_event — see Host integration.

What is not here

No typeahead. Typing a letter does not jump to a matching item. Single character matching only helps on a sorted list, and needs a keystroke buffer with a timeout to do better — which needs a clock, and this library never reads one. The navigation keys cover the same ground more predictably.

No key repeat handling, no chords beyond KeyChord. A backend key that this vocabulary has no place for — a key release, a function key beyond F(u8) — does not convert into an Event and is ignored. See KeyCode for the full list of what is representable.