Skip to content

a11y(focus): Ctrl/Cmd+Shift+L global shortcut to focus the chat input#320

Merged
mbektas merged 2 commits into
plmbr:mainfrom
pjdoland:a11y/focus-chat-input
May 19, 2026
Merged

a11y(focus): Ctrl/Cmd+Shift+L global shortcut to focus the chat input#320
mbektas merged 2 commits into
plmbr:mainfrom
pjdoland:a11y/focus-chat-input

Conversation

@pjdoland
Copy link
Copy Markdown
Collaborator

@pjdoland pjdoland commented May 18, 2026

Summary

Keyboard-first users had no shortcut to land focus on the NBI chat prompt. Reaching it required clicking the side-panel tab and then tabbing past every intervening control in the sidebar.

Solution

Register a JupyterLab command notebook-intelligence:focus-chat-input bound to Accel Shift L (Ctrl+Shift+L on Linux/Windows, Cmd+Shift+L on macOS). The handler activates the NBI sidebar via app.shell.activateById(panel.id) and dispatches a copilotSidebar:focusPrompt CustomEvent. The React sidebar listens for the event and focuses promptInputRef.current, retrying across up to 10 animation frames so the cold-collapsed-sidebar case (multi-frame mount) still lands.

Using a CustomEvent instead of document.querySelector('#sidebar-user-input textarea') matches the existing copilotSidebar:runPrompt / copilotSidebar:activeDocumentChanged / copilotSidebar:addOutputContext pattern, keeps the command handler decoupled from the DOM id, and lets the React side use the ref it already owns.

Also added to the command palette under "Notebook Intelligence" for discoverability.

Testing

  • jlpm tsc --noEmit clean. jlpm lint:check clean. jlpm jest 181 passed.
  • Six-reviewer pass replaced the original querySelector + single-rAF approach with the CustomEvent + multi-frame retry pattern.

Risks / follow-ups

  • The shortcut applies globally (selector: 'body'). The JupyterLab command-registry shortcut model lets users remap or remove it via their keyboardShortcuts settings.
  • A Galata regression test that presses the binding and asserts focus lands on the textarea is deferred.
  • Other NBI activate-panel sites use tabsmenu:activate-by-id instead of activateById; worth aligning in a follow-up for consistency.
  • No tracked GitHub issue; audit identifier (D021) is internal.

@pjdoland pjdoland added the enhancement New feature or request label May 18, 2026
pjdoland added 2 commits May 19, 2026 06:07
Keyboard-first users had no shortcut to land focus on the chat prompt.
Reaching it required clicking the side-panel tab, then tabbing past the
skip link, sidebar header buttons, and any message-action controls.

Register a JupyterLab command (notebook-intelligence:focus-chat-input)
that activates the NBI sidebar via app.shell.activateById and focuses
the prompt textarea via a document.querySelector + .focus() pass. A
requestAnimationFrame fallback handles the case where activateById's
DOM commit hasn't landed yet on the first attempt.

Bind it to Accel Shift L (Ctrl+Shift+L on Linux/Windows, Cmd+Shift+L
on macOS) — a binding common to "focus search / focus input" actions
in other editors that doesn't collide with built-in JupyterLab keys.
Also add it to the command palette under "Notebook Intelligence" for
discoverability.
@pjdoland pjdoland force-pushed the a11y/focus-chat-input branch from 3c2c94d to 960fd2e Compare May 19, 2026 10:07
@pjdoland pjdoland added this to the 5.0.x milestone May 19, 2026
@mbektas mbektas merged commit 465e2fa into plmbr:main May 19, 2026
4 checks passed
pjdoland added a commit to pjdoland/notebook-intelligence that referenced this pull request May 22, 2026
Promotes the [Unreleased] CHANGELOG snapshot to [5.0.0] - 2026-05-22
and expands it to cover everything merged into upstream/main after
PR plmbr#287's docs refresh. Bumps package.json to 5.0.0.

CHANGELOG additions cover the post-plmbr#287 surface:

- Settings tabs: plugin marketplace picker (plmbr#284), plugin marketplace
  details + Update button (plmbr#303), per-workspace MCP disable (plmbr#286),
  JSON-paste path in Add MCP server (plmbr#285).
- Launchers: hide-with-policy (plmbr#288), brand icons for Codex / opencode
  (plmbr#325, plmbr#333), per-launch directory picker (plmbr#332).
- Chat sidebar and agentic UX: workspace @-mention in Claude mode
  (plmbr#327), reload-open-files-on-disk (plmbr#330), steered system prompt
  away from over-eager notebook creation (plmbr#336).
- Skills: multi-manifest support (plmbr#321), tracks-upstream for user-
  imported skills (plmbr#322), HTTP kill switch for the reconciler (plmbr#291).
- Accessibility: full sub-section covering plmbr#305-plmbr#320.
- Security: shell-tool sandbox (plmbr#290), Claude UI-bridge sandbox (plmbr#323),
  0o600 on encrypted token (plmbr#293), env-secret scrubbing (plmbr#295), MCP
  config shape validation (plmbr#299), XSS allowlist (plmbr#296), Copilot WS
  auth + origin (plmbr#301), GHE host detection (plmbr#292), fastmcp -> mcp SDK
  swap (plmbr#324).
- Fixed: session listing unification (plmbr#310), session preview unwrap
  (plmbr#331), down-area runtime throw (plmbr#330 follow-up), WS message-handler
  leak (plmbr#294).
- Removed: fastmcp dependency, history.jsonl session gate.

Adds a Migration note covering the five behavior changes operators
should review before upgrading from 4.x: fastmcp swap, path
sandboxes, history.jsonl gate removal, workspace @-mention pointer
shape, and the Copilot WebSocket auth/origin tightening.

Two reviewer rounds (six personas each) applied:
- Round 1 caught security overclaims (plmbr#293, plmbr#299, plmbr#323), the
  plmbr#284/plmbr#303 mis-attribution, missing migration note, 3 em dashes,
  and the stale `fastmcp==2.x.*` recommendation in the admin guide.
- Round 2 caught the missing plmbr#301 migration bullet, missing version-
  matrix 5.0.x row, missing README TOC entry, and a couple of style
  nits (sub-heading overpromise, orphan bullet).

Skipped (deferred to future PRs):
- README first-run tour mention.
- Admin guide HTTP kill-switch row in Failure-modes table.
- Terminal drag-drop trust-model precision update after plmbr#327.
- Cipher description nit in plmbr#293 (Fernet AES-128-CBC+HMAC, not
  AES-GCM).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants