Skip to content

Mobile search results panel detaches from search bar when scrolling offcanvas menu #309

Description

@h30s

Problem

On mobile screens, search is accessed through the navigation drawer (#offcanvasNav).

When a user types a query into #mkdocs-search-mobile:

  1. In theme/js/osl-search.js (lines 268–275), mkPanel() creates .osl-search-panel and appends it directly to document.body (outside the offcanvas container) with position: absolute.
  2. positionPanel() calculates the panel position relative to the main document (window.scrollY / scrollTop), and only listens to window scroll/resize events (window.addEventListener('scroll', updatePosition)).

Because the mobile menu content is inside .offcanvas-body (which has its own overflow-y: auto scroll context):

  • Scrolling inside the offcanvas menu does not trigger the window scroll listener.
  • As the user scrolls down the mobile menu drawer while search results are visible, the search results panel remains fixed to the outer page body coordinates and detaches from the search input.
  • Additionally, on narrow mobile screens (under 360px width), min-width: 320px combined with the input's left offset causes the search results panel to overflow beyond the right edge of the mobile screen.

User Impact

Mobile users searching for topics or blog posts experience a broken UI where the search results panel floats away from the search bar when they scroll through the mobile menu, or overflows off the right side of the screen on smaller devices.

Expected Behavior

  • The search results panel for the mobile search field should either be placed inside or positioned relative to the mobile menu container, or stay anchored to #mkdocs-search-mobile when scrolling inside .offcanvas-body.
  • The panel width should fit comfortably within the mobile screen without overflowing.

Relevant Code References

  • theme/js/osl-search.js (lines 268–285):
    function mkPanel() {
      const div = document.createElement('div');
      div.className = 'osl-search-panel';
      div.setAttribute('role', 'listbox');
      div.style.display = 'none';
      document.body.appendChild(div);
      return div;
    }
    
    function positionPanel(panel, inputEl) {
      const r = inputEl.getBoundingClientRect();
      const scrollY = window.scrollY || document.documentElement.scrollTop;
      const scrollX = window.scrollX || document.documentElement.scrollLeft;
      const width = Math.min(Math.max(r.width, 320), 560);
      panel.style.left = `${r.left + scrollX}px`;
      panel.style.top = `${r.bottom + scrollY + 6}px`;
      panel.style.width = `${width}px`;
    }

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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