diff --git a/assets/js/core/menu.js b/assets/js/core/menu.js index 1958dde..4ef878c 100644 --- a/assets/js/core/menu.js +++ b/assets/js/core/menu.js @@ -22,7 +22,9 @@ document.addEventListener('DOMContentLoaded', function () { syncAriaHidden(); mobileQuery.addEventListener('change', syncAriaHidden); - function toggleMenu() { + function toggleMenu(options = {}) { + const { focusOnOpen = true } = options; + // Toggle the hamburger menu menu.querySelector('svg').classList.toggle('open'); @@ -41,8 +43,10 @@ document.addEventListener('DOMContentLoaded', function () { // Move focus into sidebar when opening, restore when closing if (isOpen) { - const firstFocusable = sidebarContainer.querySelector('a, button, input, [tabindex="0"]'); - if (firstFocusable) firstFocusable.focus(); + if (focusOnOpen) { + const firstFocusable = sidebarContainer.querySelector('a, button, input, [tabindex="0"]'); + if (firstFocusable) firstFocusable.focus(); + } } else { menu.focus(); } @@ -50,7 +54,9 @@ document.addEventListener('DOMContentLoaded', function () { menu.addEventListener('click', (e) => { e.preventDefault(); - toggleMenu(); + // Pointer-initiated clicks on mobile should not force focus into the search input, + // which opens the software keyboard immediately. + toggleMenu({ focusOnOpen: e.detail === 0 }); }); // Close menu on Escape key (mobile only) diff --git a/docs/hugo_stats.json b/docs/hugo_stats.json index 0a67c8a..19ea99c 100644 --- a/docs/hugo_stats.json +++ b/docs/hugo_stats.json @@ -482,7 +482,6 @@ "hx:ltr:pl-6", "hx:ltr:pl-8", "hx:ltr:pr-0", - "hx:ltr:pr-1", "hx:ltr:pr-2", "hx:ltr:pr-4", "hx:ltr:pr-8", @@ -641,7 +640,6 @@ "hx:rtl:mr-3", "hx:rtl:mr-auto", "hx:rtl:pl-0", - "hx:rtl:pl-1", "hx:rtl:pl-2", "hx:rtl:pl-4", "hx:rtl:pl-8", diff --git a/tests/mobile-menu-focus.spec.ts b/tests/mobile-menu-focus.spec.ts new file mode 100644 index 0000000..6aa7415 --- /dev/null +++ b/tests/mobile-menu-focus.spec.ts @@ -0,0 +1,21 @@ +import { test, expect } from "@playwright/test"; + +test("clicking mobile hamburger does not focus the sidebar search input", async ({ + page, +}) => { + await page.setViewportSize({ width: 375, height: 812 }); + await page.goto("/", { waitUntil: "load" }); + + const menuButton = page.locator(".hextra-hamburger-menu"); + await expect(menuButton).toBeVisible(); + + const sidebarSearchInput = page + .locator(".hextra-sidebar-container .hextra-search-input") + .first(); + await expect(sidebarSearchInput).toBeVisible(); + + await menuButton.click(); + + await expect(menuButton).toHaveAttribute("aria-expanded", "true"); + await expect(sidebarSearchInput).not.toBeFocused(); +});