diff --git a/containers/libreportal/frontend/css/backup.css b/containers/libreportal/frontend/css/backup.css
index 94be310..06f0452 100755
--- a/containers/libreportal/frontend/css/backup.css
+++ b/containers/libreportal/frontend/css/backup.css
@@ -865,6 +865,50 @@
color: var(--text-primary);
}
+/* Export dropdown in the backup page header (Configuration tab). */
+#backup-page-header .page-header-actions {
+ position: relative;
+}
+
+.backup-export-menu {
+ position: absolute;
+ top: calc(100% + 6px);
+ right: 0;
+ z-index: 50;
+ min-width: 210px;
+ padding: 6px;
+ background: var(--card-bg);
+ border: 1px solid var(--card-border, var(--border-color));
+ border-radius: 10px;
+ box-shadow: var(--card-shadow, 0 8px 24px rgba(0, 0, 0, 0.25));
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+}
+
+.backup-export-menu[hidden] {
+ display: none;
+}
+
+.backup-export-menu-item {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ width: 100%;
+ text-align: left;
+ padding: 8px 10px;
+ background: transparent;
+ border: none;
+ border-radius: 6px;
+ color: var(--text-primary);
+ font-size: 0.85rem;
+ cursor: pointer;
+}
+
+.backup-export-menu-item:hover {
+ background: rgba(var(--text-rgb), 0.08);
+}
+
.backup-warning-banner [data-action="export-passwords"] {
flex-shrink: 0;
white-space: nowrap;
diff --git a/containers/libreportal/frontend/html/backup-content.html b/containers/libreportal/frontend/html/backup-content.html
index 5967183..a940f78 100644
--- a/containers/libreportal/frontend/html/backup-content.html
+++ b/containers/libreportal/frontend/html/backup-content.html
@@ -55,6 +55,16 @@
Refresh
+
diff --git a/containers/libreportal/frontend/js/components/backup/backup-page.js b/containers/libreportal/frontend/js/components/backup/backup-page.js
index cb528da..7eff02b 100644
--- a/containers/libreportal/frontend/js/components/backup/backup-page.js
+++ b/containers/libreportal/frontend/js/components/backup/backup-page.js
@@ -136,6 +136,14 @@ class BackupPage {
// the URL via parseTabFromUrl() at init time.
document.addEventListener('click', (e) => {
+ // Clicking outside the export dropdown (and not on its trigger) closes it.
+ const exportMenu = document.getElementById('backup-export-menu');
+ if (exportMenu && !exportMenu.hidden
+ && !e.target.closest('#backup-export-menu')
+ && !e.target.closest('#backup-primary-action')) {
+ this.toggleExportMenu(false);
+ }
+
const tabBtn = e.target.closest('.backup-layout .sidebar .category[data-backup-tab]');
if (tabBtn) {
this.switchTab(tabBtn.dataset.backupTab);
@@ -201,7 +209,7 @@ class BackupPage {
if (engineBtn) { this.openEngineDetailsModal(engineBtn); return; }
const exportBtn = e.target.closest('[data-action="export-passwords"]');
- if (exportBtn) { this.exportRepositoryPasswords(exportBtn); return; }
+ if (exportBtn) { this.toggleExportMenu(false); this.exportRepositoryPasswords(exportBtn); return; }
const dismissWarn = e.target.closest('[data-action="dismiss-config-warning"]');
if (dismissWarn) {
@@ -381,6 +389,8 @@ class BackupPage {
updatePrimaryAction() {
const btn = document.getElementById('backup-primary-action');
if (!btn) return;
+ // Switching tabs always closes the export dropdown.
+ this.toggleExportMenu(false);
if (this.currentTab === 'locations') {
btn.innerHTML = `
-