Skip to content

Commit 062cdc3

Browse files
authored
fix: add inert attribute to background content when popup is shown (#34)
* fix: add inert attribute to background content when popup is shown (#22) When the validation error popup is displayed, the modal container is moved to document.body via a portal effect so that the inert attribute can safely be applied to <main> and <header>. This prevents keyboard focus from reaching background content while the popup is open. * fix: remove hardcoded container names to allow multiple worktrees to run simultaneously * fix: use native <dialog> for validation modal to properly trap focus Replace manual inert attribute management + DOM portal approach with a native <dialog> element using showModal(). The browser's top-layer mechanism handles focus trapping and background inertness natively, fixing keyboard navigation leaking to background elements. * fix: only apply flex layout when dialog[open] to avoid overriding UA display:none * fix: remove dialog container from tab sequence with tabindex=-1
1 parent caf6f42 commit 062cdc3

1 file changed

Lines changed: 36 additions & 31 deletions

File tree

src/lib/components/filesharing/SendButton.svelte

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,16 @@
305305
306306
let yiviInfoExpanded = $state(false)
307307
let buttonRef: HTMLButtonElement | null = $state(null)
308+
let dialogRef: HTMLDialogElement | null = $state(null)
309+
310+
$effect(() => {
311+
if (!browser || !dialogRef) return
312+
if (showValidationModal) {
313+
dialogRef.showModal()
314+
} else if (dialogRef.open) {
315+
dialogRef.close()
316+
}
317+
})
308318
</script>
309319
<div class="button-container">
310320
{#if EncryptState.encryptionState === EncryptionState.Encrypting}
@@ -436,20 +446,17 @@
436446
{/if}
437447
</div>
438448

439-
{#if showValidationModal}
440-
<button type="button" class="validation-backdrop" tabindex="-1" aria-hidden="true" onclick={() => showValidationModal = false}></button>
441-
<div class="validation-modal" role="dialog" aria-modal="true">
442-
<h2 class="validation-title">{$_('filesharing.encryptPanel.validation.title')}</h2>
443-
<ul class="validation-errors">
444-
{#each validationErrors as error}
445-
<li>{error}</li>
446-
{/each}
447-
</ul>
448-
<button class="primary-btn" onclick={() => showValidationModal = false}>
449-
{$_('filesharing.encryptPanel.validation.continueButton')}
450-
</button>
451-
</div>
452-
{/if}
449+
<dialog bind:this={dialogRef} class="validation-modal" tabindex="-1" oncancel={() => showValidationModal = false}>
450+
<h2 class="validation-title">{$_('filesharing.encryptPanel.validation.title')}</h2>
451+
<ul class="validation-errors">
452+
{#each validationErrors as error}
453+
<li>{error}</li>
454+
{/each}
455+
</ul>
456+
<button class="primary-btn" onclick={() => showValidationModal = false}>
457+
{$_('filesharing.encryptPanel.validation.continueButton')}
458+
</button>
459+
</dialog>
453460

454461
<style lang="scss">
455462
.send-btn {
@@ -674,29 +681,27 @@
674681
}
675682
676683
/* Validation modal */
677-
.validation-backdrop {
678-
position: fixed;
679-
inset: 0;
680-
background: rgba(0, 0, 0, 0.45);
681-
z-index: 10;
682-
cursor: pointer;
683-
}
684-
685-
.validation-modal {
686-
position: fixed;
687-
top: 50%;
688-
left: 50%;
689-
transform: translate(-50%, -50%);
690-
background: var(--pg-general-background);
684+
dialog.validation-modal {
685+
border: none;
691686
border-radius: var(--pg-border-radius-lg);
692687
padding: 1.75rem 1.5rem 1.5rem;
693-
z-index: 11;
694688
width: 90%;
695689
max-width: 380px;
696-
display: flex;
697-
flex-direction: column;
698690
gap: 1rem;
699691
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
692+
background: var(--pg-general-background);
693+
color: var(--pg-text);
694+
}
695+
696+
/* Only apply flex layout when the dialog is open.
697+
Setting display on dialog directly overrides the UA's display:none for closed dialogs. */
698+
dialog.validation-modal[open] {
699+
display: flex;
700+
flex-direction: column;
701+
}
702+
703+
dialog.validation-modal::backdrop {
704+
background: rgba(0, 0, 0, 0.45);
700705
}
701706
702707
.validation-title {

0 commit comments

Comments
 (0)