Skip to content

Theme switch while start menu is open strands DOM focus on body (opener mirror disconnected) #35

Description

@Xuepoo

Summary

When the start menu is open and the user switches themes, DOM focus ends up stranded on <body> after dismissal. Escape, click-outside, and app-launch all run through closeStartMenu(), whose opener-restoration silently no-ops because the captured opener element was destroyed with the old taskbar.

Found during review of PR #31 (WEB-0035 fix round, finding F3).

Reproduction

  1. Focus the Start button (or any taskbar control).
  2. Open the start menu — openStartMenu captures the focused element into openerFocus (src/desktop/main.ts:471).
  3. Switch the theme (Settings → any other era) while the menu is open.
  4. Dismiss the menu (Escape / click outside / launch an app).

Expected: focus returns to a sensible control (the Start button).
Actual: document.activeElement is <body>.

Root cause

applyTheme (src/desktop/main.ts:81-82) calls installWebosTaskbar() — which destroys the old WebOSTaskbar together with its a11y mirrors (src/desktop/main.ts:415-418) — before closeStartMenu(). The PX-0077 restoration in closeStartMenu (src/desktop/main.ts:460-463) then calls .focus() on the captured opener, but that node is disconnected: focusing a detached element is a silent no-op, and the guard (activeElement === body) passes precisely because the destruction already dropped focus to <body>.

Two constraints make the fix non-trivial:

  • Reordering alone does not help: closing the menu first restores focus onto the old Start mirror, which installWebosTaskbar destroys immediately afterwards.
  • An immediate fallback cannot target the new Start button either: the rebuilt taskbar's a11y mirror only exists after the engine's next a11y sync pass (which runs on the following frame).

Suggested direction

Re-validate the captured opener at restore time: if it is still connected, restore as today; otherwise fall back to the live taskbar's Start tile, deferring the actual .focus() past the next a11y sync (guarded so it yields if something else took focus meanwhile).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions