Skip to content

Admin dropdown positioned incorrectly after scrolling #2327

Description

@matjazpotocnik

Admin navigation dropdown menus are positioned too far down the page when opened after the document has been scrolled.

This occurs when a theme applies position: fixed to .pw-dropdown-menu. ProcessWire uses jQuery UI Position to place the menu, which produces document-relative top and left coordinates. Fixed-position elements require viewport-relative coordinates, so the current scroll offset is effectively added to the menu position.

Steps to reproduce

  1. Use AdminThemUikit Konkat.
  2. Open an admin page with enough content to scroll.
  3. Scroll down the page.
  4. Hover over a primary navigation item such as Setup.
  5. Observe the dropdown position.

Actual behavior

The dropdown appears below its intended position by approximately the current document scroll offset. For example, with the document scrolled by approximately 300px, a dropdown that should start directly below the masthead is positioned approximately 300px farther down the viewport. The displacement increases as the page is scrolled farther.

Expected behavior

The dropdown should open directly below its navigation trigger regardless of the current horizontal or vertical document scroll position.
It should also remain attached to the sticky masthead if the document is scrolled while the menu is open.

Root cause

The dropdown is positioned in wire/templates-admin/scripts/main.js with:

$ul.position(position).css('z-index', 200);

jQuery UI Position calculates document-relative coordinates. This is correct for its expected position: absolute menu. However, Konkat theme override the menu with:

.pw-dropdown-menu[data-at="left bottom"] {
	position: fixed !important;
}

A fixed element interprets top and left relative to the viewport. The document scroll offsets therefore need to be removed from the coordinates calculated by jQuery UI.

Suggested fix

After jQuery UI positions the dropdown, convert the generated coordinates from document-relative to viewport-relative coordinates when the menu’s computed position is fixed.

 if(my) position.my = my;
 if(at) position.at = at;
 $ul.position(position).css('z-index', 200);
+if($ul.css('position') === 'fixed') {
+	$ul.css({
+		top: Number.parseFloat($ul.css('top')) - window.pageYOffset,
+		left: Number.parseFloat($ul.css('left')) - window.pageXOffset
+	});
+}

This preserves the existing behavior for normal absolutely positioned menus and only adjusts menus whose final computed position is fixed.

The corresponding production file, wire/templates-admin/scripts/main.min.js, should be regenerated after changing the source.

Why this approach

  • Does not assume a particular masthead height.
  • Works with different themes and responsive masthead dimensions.
  • Supports vertical and horizontal document scrolling.
  • Preserves existing jQuery UI alignment options such as data-my and data-at.
  • Does not affect absolutely positioned dropdowns.
  • Keeps an already-open fixed menu attached to a sticky masthead while scrolling.

Validation

The suggested fix was tested with the page at vertical scroll positions:

  • 0px
  • 137px
  • 421px
  • 530px

At each position, the dropdown’s viewport top matched the actual bottom of its navigation trigger. Pages, Setup, Modules, Access, and the user dropdown were tested.

The menu also remained in the correct position when the page was scrolled while the dropdown was already open.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions