Implement Two-Tier Escape Key Behavior: Remove Focus from Editable Fields First, Then Dismiss Overlays #2881
Zak Siddiqui opened 5 days ago

Relates to investigation from Issue 2880: Can the Escape key be configured to first blur focus from editable text fields before triggering OneDev's built-in pane visibility shortcut?

Summary

Currently, pressing Escape in OneDev always triggers overlay dismiss actions (closing modals, sidebars, tooltips, etc.) regardless of whether an editable text field has focus. This breaks a widely expected convention where pressing Escape should first cause the focused input to lose focus, allowing keyboard-driven and accessibility workflows to proceed.

We propose a two-tier Escape key behavior:

  1. First Escape press (editable element has focus) → the element loses focus; no overlays are dismissed.
  2. Second Escape press (no editable element has focus) → existing dismiss/close behavior proceeds as normal.

Investigation Findings

An investigation into the current Escape key handling in OneDev revealed the following:

Browser Default Clarification

Pressing Escape does not automatically remove focus from <input> / <textarea> elements in Chrome, Firefox, or Safari. This "blur-on-Escape" behavior is an application-level convention, not a browser built-in.

Where Escape Is Currently Intercepted

A global document-level keydown handler in server-core/.../web/page/base/base.js calls preventDefault() on every Escape press:

$(document).keydown(function(e) {
    if (e.keyCode == 27) // ESC
        e.preventDefault();
});

Additional Escape handlers exist in the following files, all dismissing UI overlays:

LocationAction
layout.jsCloses the mobile sidebar (sidebar-docked)
side-info.jsCloses the side-info panel (overlay mode only)
modal.jsCloses the topmost modal (with dirty-form confirm)
floating.jsCloses floating / dropdown panels
symbol-tooltip.js, source-view.js, etc.Closes tooltips / popovers

None of these handlers call activeElement.blur() or otherwise cause the focused element to lose focus.

Existing Focus-Aware Shortcut Patterns

The bundled jQuery Hotkeys plugin (server-core/.../web/asset/hotkeys/jquery.hotkeys.js) already implements focus-aware filtering via filterInputAcceptingElements, filterTextInputs, and filterContentEditable. However, the Escape dismiss handlers listed above do not use this filter — they listen with raw $(document).on("keydown", ...) and only exclude a few overlay widgets (e.g., flatpickr, select2).


Proposed Implementation

  1. In a central Escape handler (or at the start of each existing dismiss handler), check if document.activeElement is an editable control:

    • <input>, <textarea>, <select>
    • [contenteditable]
    • CodeMirror instances
    • Other rich-text editors
  2. If an editable element has focus:

    • Call activeElement.blur() (or equivalent) to remove focus.
    • return early — do not proceed with overlay dismissal.
  3. If no editable element has focus:

    • Proceed with existing dismiss/close behavior as today.
  4. Reuse the focus-checking logic already present in the jQuery Hotkeys plugin (filterInputAcceptingElements / filterTextInputs / filterContentEditable) to maintain consistency.


Design Caveats to Consider

  • Markdown / CodeMirror editors already use Escape for their own UI (hints, fullscreen, etc.) — these should take priority.
  • Date pickers (flatpickr), Select2, and color pickers already special-case Escape — ensure no conflicts.
  • Dirty form state: Removing focus from a field with unsaved changes before a modal close could change the leave-confirm UX unexpectedly.

Acceptance Criteria

  •  Pressing Escape while an editable text field has focus causes that field to lose focus without dismissing any overlays.
  •  Pressing Escape again (with no editable field focused) triggers the existing dismiss/close behavior (modals, sidebars, tooltips, etc.).
  •  Special editor Escape behaviors (CodeMirror hints, flatpickr, Select2) continue to work correctly and take priority.
  •  Accessibility tools relying on keyboard shortcuts after Escape are no longer blocked by lingering input focus.
1/1
Type
Improvement
Priority
Normal
Assignee
Labels
No labels
Issue Votes (0)
Watchers (2)
Reference
OD-2881
Please wait...
Connection lost or session expired, reload to recover
Page is in error, reload to recover