Skip to content

[2.x] Fix search modal overlapping the navigation drawer on mobile - #4811

Merged
imorland merged 1 commit into
flarum:2.xfrom
karl-bullock:mobile-search-drawer-glitch
Jul 23, 2026
Merged

[2.x] Fix search modal overlapping the navigation drawer on mobile#4811
imorland merged 1 commit into
flarum:2.xfrom
karl-bullock:mobile-search-drawer-glitch

Conversation

@karl-bullock

Copy link
Copy Markdown
Contributor

What / why

On phones the global search input is rendered inside the slide-out navigation drawer. Tapping it opens the full-screen SearchModal, but the drawer is never closed first, so it visibly overlaps the modal while the modal animates in. The screen "glitches" for a moment and then corrects itself once the modal settles on top.

Root cause

.App-drawer is positioned at z-index: var(--zindex-modal) (1050), the same base the modal system builds on:

  • ModalManager -> calc(var(--zindex-modal) + var(--modal-number))
  • .Modal-backdrop -> calc(var(--zindex-modal) + var(--modal-count) - 2)

While the modal mounts, --modal-number is 0, so for ~50-150ms:

  • the still-open drawer stays at 1050 and covers the left of the screen,
  • the modal backdrop resolves to 1048/1049, i.e. below the drawer, so only the area the drawer does not cover gets dimmed, and
  • ModalManager then mounts at 1050 and the modal slides up over the drawer.

The net effect is the drawer overlapping the opening search modal before it is finally covered.

Fix

Close the drawer as soon as search is activated, in the Search onclick handler, before the modal is shown. Placing it here rather than inside openSearchModal lets the drawer finish its slide-out during the existing 150ms delay, so the modal opens over the page instead of over the drawer. Hiding it at modal-show time is too late: the drawer's 0.2s slide-out then races the modal and the overlap still shows.

app.drawer.hide() returns early when the drawer is not open, so this is a no-op on wider screens and in the admin frontend (the search component is shared, and app.drawer is created by the common Application).

Testing

Reproduced on a clean 2.0.0-rc.5 install at a 390px viewport, opening the drawer and tapping search as both a guest and a logged-in user. Before the change the drawer overlaps the opening modal for ~150ms; after it, the drawer slides out first and the modal opens cleanly. I confirmed frame by frame that the .App-navigation header (z-index 1000/1001) is never the element on top, so the mis-layering is the drawer versus the modal, not the header.

On phones the global search lives inside the slide-out drawer, which shares its
z-index base (--zindex-modal) with the modal system. Opening the search modal
without closing the drawer left it overlapping the modal for ~150ms while the
modal animated in. Hide the drawer as search is activated so it slides out before
the modal appears.
@karl-bullock
karl-bullock requested a review from a team as a code owner July 11, 2026 00:19
@imorland imorland added this to the 2.0.0-rc.6 milestone Jul 23, 2026

@imorland imorland left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified the diagnosis and it holds up: .App-drawer sits at z-index: var(--zindex-modal) (1050), and while the modal mounts its backdrop resolves just below that, so the still-open drawer overlaps the opening modal. Closing the drawer in the onclick before the modal is shown is the right fix, and the change is safe.

One correction on the reasoning, though — the description says app.drawer.hide() "returns early when the drawer is not open, so this is a no-op." That's not quite right: hide() runs focusTrap.deactivate(), removeListener(resizeHandler) and closeWatcher?.destroy() before the if (!this.isOpen()) return guard, so those always execute. It's harmless here — and safe by precedent, since Page.tsx already calls app.drawer.hide() unconditionally on every page load — but it isn't an early-return no-op. Worth being accurate about, in case that pre-guard code ever grows a real side effect.

Not blocking. Approving.

@imorland
imorland merged commit 3f3d99a into flarum:2.x Jul 23, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants