From 84d1efc27168181befc2832c9b7e266b18de787a Mon Sep 17 00:00:00 2001 From: claude Date: Tue, 16 Jun 2026 12:55:39 +0000 Subject: [PATCH] fix: use
/ for Pug language picker to get native toggle The manual JS click-handler approach (tried with stopPropagation, containment check, and mousedown variants) never worked reliably on login/password/settings pages. The browser's native
/ toggle behaviour requires no JavaScript and is immune to Bootstrap JS or React event delegation interference. The inline script now only builds the return_to hrefs and handles outside-click-to-close (setting details.open=false). The CSS gains a .language-picker-details rule that sets position:relative so the absolutely-positioned dropdown-menu is positioned correctly, and details[open] .dropdown-menu { display: block } to show the menu. The #language-picker-toggle id remains on the so the existing CSS (cursor, text-decoration, material-symbols alignment) continues to apply. The React LanguagePicker is unaffected. Co-Authored-By: Claude Sonnet 4.6 --- .../web/app/views/layout/language-picker.pug | 30 +++++-------------- .../stylesheets/components/footer.scss | 23 ++++++++++++++ 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/services/web/app/views/layout/language-picker.pug b/services/web/app/views/layout/language-picker.pug index 1444f29045..217fb02a9f 100644 --- a/services/web/app/views/layout/language-picker.pug +++ b/services/web/app/views/layout/language-picker.pug @@ -1,9 +1,6 @@ li.language-picker - .dropdown - button#language-picker-toggle.btn-inline-link( - type='button' - aria-haspopup='true' - aria-expanded='false' + details.language-picker-details + summary#language-picker-toggle.btn-inline-link( aria-label=translate('select_a_language') translate='no' ) @@ -25,10 +22,9 @@ li.language-picker )= settings.translatedLanguages[lngCode] script. (function () { - var toggle = document.getElementById('language-picker-toggle') - var menu = toggle && toggle.parentElement.querySelector('.dropdown-menu') - if (!toggle || !menu) return - // Build return_to at runtime so the href reflects the actual current path + var details = document.querySelector('.language-picker-details') + var menu = details && details.querySelector('.dropdown-menu') + if (!details || !menu) return menu.querySelectorAll('a[data-lng]').forEach(function (a) { var lng = a.getAttribute('data-lng') a.href = @@ -37,20 +33,10 @@ li.language-picker '&return_to=' + encodeURIComponent(window.location.pathname) }) - var picker = toggle.closest('.language-picker') - function close() { - menu.classList.remove('show') - toggle.setAttribute('aria-expanded', 'false') - } - toggle.addEventListener('click', function () { - var opening = !menu.classList.contains('show') - menu.classList.toggle('show', opening) - toggle.setAttribute('aria-expanded', String(opening)) - }) - document.addEventListener('mousedown', function (e) { - if (!picker || !picker.contains(e.target)) close() + document.addEventListener('click', function (e) { + if (!details.contains(e.target)) details.open = false }) document.addEventListener('keydown', function (e) { - if (e.key === 'Escape') { close(); toggle.focus() } + if (e.key === 'Escape') details.open = false }) })() diff --git a/services/web/frontend/stylesheets/components/footer.scss b/services/web/frontend/stylesheets/components/footer.scss index 6ec952c9d7..8a61d8748a 100644 --- a/services/web/frontend/stylesheets/components/footer.scss +++ b/services/web/frontend/stylesheets/components/footer.scss @@ -203,6 +203,7 @@ footer.site-footer { vertical-align: middle; } +// Applies to both the React language picker toggle (button) and the Pug one (summary) #language-picker-toggle { text-decoration: none; cursor: pointer; @@ -222,6 +223,28 @@ footer.site-footer { } } +// Pug language picker uses
/ for native toggle behaviour +.language-picker-details { + display: inline-block; + position: relative; + + summary { + list-style: none; + + &::-webkit-details-marker { + display: none; + } + + &::marker { + content: ''; + } + } + + &[open] .dropdown-menu { + display: block; + } +} + .language-picker .dropdown-menu { // Open upward — Popper.js isn't available on all page layouts top: auto;