guide · computers

ABS Keyboard Shortcuts: n, r, b (No Prefix)

ABS ships three single-letter shortcuts, no prefix, no modifiers, no armed state. The bindings, why we left a g-prefix design behind, what we considered and cut, and the skip-rules.

July 14, 2026 · By Alastair Fraser

A friendly retro robot at a three-key mechanical keyboard whose only keys are N, R, and B, each emitting a thin route line that resolves into a labeled page — News, Reviews, Books — while a faint ghost of a 'G' prefix key sits ignored in the corner.

The three bindings

Press n, r, or b anywhere on ABS to jump to a top-level destination. No prefix. No chord. No armed state. No toast.

KeyGoes toPath
nNews/news/
rReviews/reviews/
bThe Agent Advantage book/books/the-agent-advantage/

The implementation lives in public/scripts/app.js as an IIFE with a single source of truth — a SHORTCUTS object — so any future UI hint that wants to surface the bindings reads from the same map:

var SHORTCUTS = {
  'n': '/news/',
  'r': '/reviews/',
  'b': '/books/the-agent-advantage/',
};

The handler listens on document, looks up SHORTCUTS[e.key.toLowerCase()], and calls location.assign(href) after e.preventDefault(). Three lines of bind logic around a four-line table.

The migration away from a “g” prefix

The first design considered for ABS mimicked GitHub and Gmail: a two-key chord like g then n. On paper the prefix buys you a large addressable namespace without conflicting with browser shortcuts. In practice, on a content site with a small surface, it buys you almost nothing and costs a lot.

The case against a prefix on ABS:

  1. The namespace is small. A prefix buys you slots for destinations that do not exist yet. Speculative shortcuts rot — readers forget a g chord for a route that shipped and then got renamed.
  2. Two-key chords double the latency. A single key reaches the destination in the same interval that the reader’s brain already spent on the decision.
  3. Prefixes fail the discoverability test. A new reader who presses g sees nothing. The ABS shortcut model fails open — n is a single letter, n for News, the same letter that begins the word on the top-bar link the reader has already seen.

The design landed on commit afb1ddc (Phase 5 of the SDP build) with a comment that names the constraint directly: “three bindings only, all single letters. No ‘g’ prefix, no armed state, no toast. The user accepts that guides is reachable from the rail / hamburger drawer / top bar; no shortcut for guides.”

The cut is deliberate. Guides is the most-visited ABS section, but the keyboard is not the right surface — readers searching for guides are usually searching for a specific guide, not the section index. They belong on the search bar, not on a shortcut.

Why three is enough

The number was chosen by cutting. Considered and rejected:

ConsideredCut because
g/guides/Guides need search, not navigation. A shortcut that lands on a section index is a half-measure.
h/ (home)One click away in the top bar and the browser back button already covers it.
s → focus searchAlready taken by the search bar’s /-focus shortcut.
? → keyboard helpNot enough shortcuts to need an overlay. The reader can read this guide.
j / k → next / previousHold for a separate guide if listing pages ever grow a real keyboard model.
1-9 → top nav by positionPosition-based bindings break the moment the nav reorders. Letter bindings survive renames.
Esc → close any overlayEsc is a handler the mobile drawer and book submenu already wire. The keyboard IIFE yields to it.

The rule that emerged: a shortcut earns its key if (a) the destination is a top-level surface readers revisit, (b) the destination is not better reached by the search bar, and (c) the letter is not already spoken for. News, Reviews, and the book pass all three.

The five skip-rules

The shortcut handler bails before navigating in five situations. The order matters: cheap checks run first.

document.addEventListener('keydown', function (e) {
  // 1. Modifier keys belong to the browser / OS.
  if (e.ctrlKey || e.metaKey || e.altKey || e.shiftKey) return;
  // 2. IME composition is active (CJK input, dead keys).
  if (e.isComposing || e.keyCode === 229) return;
  // 3. Focus is on an editable surface.
  var t = e.target;
  if (isEditable(t)) return;
  // 4. Escape — let the existing overlay handlers win.
  if (e.key === 'Escape') return;
  // 5. The key isn't bound — exit before preventDefault.
  var href = SHORTCUTS[e.key.toLowerCase()];
  if (!href) return;

  e.preventDefault();
  location.assign(href);
});

Rule 1 — modifier keys. Ctrl, Cmd, Alt, Shift, and Meta all surrender the event to the browser or OS. Ctrl+r is reload; Cmd+n opens a new window. The handler only fires on a bare key, so it never collides with copy-paste, tab-switching, devtools, or any OS chord.

Rule 2 — IME composition. e.isComposing is true while an IME session is open — Chinese, Japanese, Korean, plus dead-key Latin input. The fallback e.keyCode === 229 catches older Android browsers that did not set isComposing. Without this check, pressing n to type would navigate away from the form. Sites that skip it ship a navigation bug for every CJK reader on every keypress.

Rule 3 — focus is on an editable surface. isEditable(el) returns true for INPUT, TEXTAREA, SELECT, any element with isContentEditable === true, and any element with aria-disabled="true". If focus is on any of those, the keypress is treated as typing and the shortcut yields. aria-disabled is included as a courtesy: a disabled-by-ARIA element is one the screen reader announced as not interactive, and the handler respects that signal even though the element is still focusable.

Rule 4 — Escape. Escape is the universal “close what is open” key. The mobile drawer, the book submenu, and any future disclosure widget all listen for it. If a submenu is open and the reader presses Esc, the keyboard IIFE returns immediately so the existing handler can run. Without this check, preventDefault on Esc would break the close behavior of every overlay.

Rule 5 — unbound key. The last check is a table lookup. If the lowered key is not in SHORTCUTS, the handler returns without calling preventDefault. This is what allows every other keypress to do its normal job — t for scroll, space for page-down, enter for submit. preventDefault is only called when a navigation actually fires.

Verification

#CheckResult
1n on / navigates to /news/Pass
2r on /guides/ navigates to /reviews/Pass
3b on /reviews/ navigates to /books/the-agent-advantage/Pass
4n while focused on the search input types nPass
5Cmd+r reloads, does not navigatePass
6n during IME composition types, does not navigatePass
7Esc with the mobile drawer open closes the drawerPass
8t does nothingPass
9preventDefault only fires on a real navigationPass

Sources

Last verified: 2026-07-14 against the live keyboard IIFE at public/scripts/app.js lines 232-291, commit afb1ddc (Phase 5 of the SDP build).

Sources

#keyboard#shortcuts#ux#javascript#abs

Submit a take

Have a different read on this? Drop a comment below — your email isn't published, and I read every one. Nothing leaves the site until I approve it.

Your email address will not be published. Required fields are marked.