fix: overlay initial focus targets enabled element (closes #69) #116
Closed
Rockachopa
wants to merge 2 commits from
door/issue-69 into main
pull from: door/issue-69
merge into: Timmy_Foundation:main
Timmy_Foundation:main
Timmy_Foundation:fix/200
Timmy_Foundation:step35/201-intake-submission-from-image
Timmy_Foundation:step35/203-intake-submission-from-image
Timmy_Foundation:step35/200-intake-submission-from-test
Timmy_Foundation:step35/197-door-1-build-anonymous-intake
Timmy_Foundation:fix/121
Timmy_Foundation:fix/99
Timmy_Foundation:fix/130
Timmy_Foundation:fix/141-crisis-contract
Timmy_Foundation:burn/20260421-0040-fix
Timmy_Foundation:fix/101
Timmy_Foundation:fix/134
Timmy_Foundation:fix/135
Timmy_Foundation:fix/100
Timmy_Foundation:fix/123
Timmy_Foundation:fix/133
Timmy_Foundation:fix/36
Timmy_Foundation:fix/37
Timmy_Foundation:fix/96
Timmy_Foundation:fix/41
Timmy_Foundation:fix/673-genome-door
Timmy_Foundation:fix/95
Timmy_Foundation:fix/97
Timmy_Foundation:fix/73-toast-alerts
Timmy_Foundation:fix/131-voice-analysis
Timmy_Foundation:fix/59-about-footer-link
Timmy_Foundation:fix/59-1776403637
Timmy_Foundation:burn/59-1776304777
Timmy_Foundation:fix/59-about-link
Timmy_Foundation:fix/136-crisis-metrics-cli
Timmy_Foundation:feat/136-cli-metrics
Timmy_Foundation:fix/38
Timmy_Foundation:fix/75
Timmy_Foundation:fix/673
Timmy_Foundation:door/issue-38
Timmy_Foundation:fix/141
Timmy_Foundation:fix/59
Timmy_Foundation:burn/73-inline-toast
Timmy_Foundation:burn/1601-crisis-logic-alignment
Timmy_Foundation:burn/123-1776303473
Timmy_Foundation:burn/73-1776303595
Timmy_Foundation:burn/123-1776303595
Timmy_Foundation:fix/130-behavioral
Timmy_Foundation:feat/136-crisis-metrics-cli
Timmy_Foundation:feat/134-unified-crisis-scorer
Timmy_Foundation:feat/133-behavioral-detection
Timmy_Foundation:feat/131-voice-analysis
Timmy_Foundation:burn/35-1776218265
Timmy_Foundation:fix/132
Timmy_Foundation:burn/99-1776264183
Timmy_Foundation:burn/99-1776264262
Timmy_Foundation:fix/136
Timmy_Foundation:fix/123-duplicate-patterns-6213
Timmy_Foundation:fix/burn-crisis-logic-alignment
Timmy_Foundation:burn/37-1776264184
Timmy_Foundation:burn/101-1776264183
Timmy_Foundation:burn/69-1776264183
Timmy_Foundation:burn/101-1776264262
Timmy_Foundation:burn/38-1776264184
Timmy_Foundation:burn/41-1776264184
Timmy_Foundation:burn/36-1776264184
Timmy_Foundation:burn/101-1776263878
Timmy_Foundation:door/issue-35
Timmy_Foundation:fix/101-crisis-ab-testing
Timmy_Foundation:fix/94-safety-plan-inline-feedback
Timmy_Foundation:feat/safety-plan-history
Timmy_Foundation:fix/96-safety-plan-version-history
Timmy_Foundation:fix/97-crisis-metrics-endpoint
Timmy_Foundation:fix/98-offline-crisis-resources
Timmy_Foundation:fix/crisis-overlay-debounce
Timmy_Foundation:fix/90-overlay-focus-enabled-element
Timmy_Foundation:fix/95-overlay-keyboard-nav
Timmy_Foundation:fix/59-footer-about-link
Timmy_Foundation:fix/95-crisis-overlay-keyboard-nav
Timmy_Foundation:fix/overlay-escape-key
Timmy_Foundation:burn/73-1776218082
Timmy_Foundation:burn/73-1776218180
Timmy_Foundation:burn/36-1776218258
Timmy_Foundation:fix/38-safety-plan-in-chat
Timmy_Foundation:burn/69-1776218206
Timmy_Foundation:burn/69-1776217968
Timmy_Foundation:burn/37-1776217996
Timmy_Foundation:burn/73-1776217949
Timmy_Foundation:door/issue-73
Timmy_Foundation:burn/41-1776217979
Timmy_Foundation:fix/issue-75-1
Timmy_Foundation:fix/issue-73-2
Timmy_Foundation:fix/67-focus-trap
Timmy_Foundation:fix/65-modal-focus-trap
Timmy_Foundation:fix/69-initial-focus
Timmy_Foundation:fix/59-about-route
Timmy_Foundation:fix/59-footer-about
Timmy_Foundation:dispatch/38-1776180746
Timmy_Foundation:dispatch/40-1776180746
Timmy_Foundation:am/38-1776166469
Timmy_Foundation:am/40-1776166469
Timmy_Foundation:am/41-1776166469
Timmy_Foundation:dispatch/41-1776180746
Timmy_Foundation:dawn/38-1776130053
Timmy_Foundation:triage/38-1776129677
Timmy_Foundation:q/38-1776129480
Timmy_Foundation:queue/38-1776129201
Timmy_Foundation:burn/59-1776131200
Timmy_Foundation:burn/37-1776131000
Timmy_Foundation:dawn/40-1776130053
Timmy_Foundation:dawn/41-1776130053
Timmy_Foundation:triage/40-1776129677
Timmy_Foundation:triage/41-1776129677
Timmy_Foundation:q/41-1776129480
Timmy_Foundation:q/40-1776129480
Timmy_Foundation:queue/41-1776129201
Timmy_Foundation:queue/40-1776129201
Timmy_Foundation:whip/38-1776128804
Timmy_Foundation:whip/40-1776128804
Timmy_Foundation:whip/41-1776128804
Timmy_Foundation:feat/session-crisis-tracking
Timmy_Foundation:burn/20260413-1620-dying-detection-dedup
Timmy_Foundation:feat/crisis-synthesizer
Timmy_Foundation:feat/compassion-router-wiring
Timmy_Foundation:fix/deduplicate-crisis-detectors
Timmy_Foundation:feat/compassion-router-gateway
Timmy_Foundation:fix/dedup-crisis-detector
Timmy_Foundation:fix/remove-bridge-false-positive
Timmy_Foundation:burn/20260413-0406-fix
Timmy_Foundation:burn/rescue-crisis
Timmy_Foundation:burn/20260413-0213-vps-deploy
Timmy_Foundation:fix/test-none-input
Timmy_Foundation:burn/20260412-0812-vps-prep
Timmy_Foundation:burn/20260412-1851-crisis-system
Timmy_Foundation:burn/20260409-1931-crisis-prompt
Timmy_Foundation:burn/20260410-2030-crisis-active-listening
Timmy_Foundation:fix/add-smoke-test
Timmy_Foundation:feat/ci-sanity-checks
Timmy_Foundation:feat/detailed-crisis-guidelines
Timmy_Foundation:burn/20260409-1230-issue4-crisis-backend
Timmy_Foundation:feat/sovereign-heart-router
Timmy_Foundation:feature/resilience
Timmy_Foundation:feature/content-pages
Timmy_Foundation:feature/dying-detection
Timmy_Foundation:feature/crisis-system-prompt
Labels
Clear labels
backend
batch-pipeline
content
deploy
epic
frontend
hardening
infra
priority:critical
priority:high
priority:medium
protocol
throughput-10x
token-masterplan
velocity-engine
Backend / API
batch-pipeline label
Content, copy, testimony
Deployment / go-live
Epic / parent issue
Frontend / UI
Resilience, fallback, security
Infrastructure, DevOps, deployment
Must have for launch
Important for launch
Nice to have at launch
Crisis detection protocol
throughput-10x label
token-masterplan label
Auto-generated by velocity engine
No Label
Milestone
No items
No Milestone
Projects
Clear projects
No project
Assignees
Rockachopa
Timmy
allegro
antigravity
bezalel
claude
codex-agent
ezra
gemini
google
grok
hermes
kimi
manus
perplexity
sonnet
Clear assignees
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: Timmy_Foundation/the-door#116
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Delete Branch "door/issue-69"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #69
Supersedes PR #107 (adds focus recovery for escaped focus)
Problem
When the crisis overlay opens,
showOverlay()disables the dismiss button for a 10-second countdown, then callsoverlayDismissBtn.focus(). Disabled buttons cannot receive focus, so keyboard and assistive-technology users lose context at the most critical moment.Fix
.overlay-call) instead — always enabled, most important actionChanges
index.html: Focus.overlay-callon open, Escape handler, focus recovery in traptests/test_crisis_overlay_focus_trap.py: 3 new regression testsWhy this supersedes #107
PR #107 correctly fixes the initial focus bug but does not handle focus recovery if focus escapes the overlay. This PR adds that safety net, which is critical for assistive-technology users.
Testing
Solid accessibility fix. The changes are well-scoped and correct:
Initial focus target: Moving focus from the disabled dismiss button to the always-enabled Call 988 link is the right call — focusing a disabled element is a WCAG violation and breaks screen reader workflows.
Escape key handling: Properly gated behind
overlayDismissBtn.disabledcheck so users cannot dismiss the crisis overlay prematurely during the safety countdown. Good use ofe.preventDefault()to avoid interference.Focus recovery: The
crisisOverlay.contains(document.activeElement)guard catches the edge case where focus escapes the overlay (e.g., via browser extension or script), which strengthens the focus trap.Tests: The three new test cases validate the structural changes at the HTML/JS level. They check for the correct patterns without being brittle.
One minor note: the Escape key handler fires
overlayDismissBtn.click()— this assumes the dismiss button's click handler exists and handles cleanup. That dependency is implicit but acceptable given the single-file structure.Approved — this improves accessibility for a safety-critical overlay.
Auto-approved: clean merge, no conflicts.
⚠️ Required CI checks are not passing. Please ensure all tests pass before requesting merge.
Good fix for issue #69. The changes are correct and well-targeted:
!overlayDismissBtn.disabled, preventing premature dismissal during the countdown.crisisOverlay.contains(document.activeElement)catches focus escaping the overlay.Tests are structural (checking HTML source) which is appropriate for this project.
One minor note: the focus recovery check uses
crisisOverlay.contains()which is a cleaner approach than what PR #104 does (iterating through focusable elements). If both PRs are intended to merge, there will be a conflict in the focus trap logic — coordinate with PR #104.Approved.
Review: fix: overlay initial focus targets enabled element
Good fix addressing issue #69 — focuses Call 988 link on overlay open and adds Escape key dismissal. Also adds focus recovery when focus escapes the overlay.
Overlaps with PRs #126, #84, and #104 — all address issue #69 and/or #95. Only one should merge; close duplicates.
The Escape key handler correctly checks
!overlayDismissBtn.disabledbefore dismissing — this prevents premature dismissal during the countdown. Good.Focus recovery using
crisisOverlay.contains(document.activeElement)is cleaner than PR #104's approach of iterating focusable elements. Prefer this version.Tests look good.
Closing: Superseded by #126.
Pull request closed