Skip to content

Commit 2810665

Browse files
committed
fix: make navbar not focusable if hidden
also drop unused sidebarEl
1 parent a7eb0a7 commit 2810665

1 file changed

Lines changed: 35 additions & 0 deletions

File tree

‎src/lib/components/layout/sidebar/Sidebar.svelte‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import type { Component } from 'svelte';
66
import IconChevronLeft from 'virtual:icons/material-symbols/chevron-left';
77
import IconChevronRight from 'virtual:icons/material-symbols/chevron-right';
8+
import { MediaQuery } from 'svelte/reactivity';
89
import type { NavItem } from '$lib/types/navigation.js';
910
import { getNavSections } from './nav-items.js';
1011
@@ -20,6 +21,10 @@
2021
2122
const sections = $derived(getNavSections({ storageBrowserEnabled }));
2223
24+
// make mobile navbar not focusable if its hidden
25+
const isDesktop = new MediaQuery('min-width: 64rem', true);
26+
const hiddenFromUser = $derived(!isDesktop.current && !mobileOpen);
27+
2328
function isActive(href: string): boolean {
2429
if (href === '/') return page.url.pathname === '/';
2530
return page.url.pathname.startsWith(href);
@@ -40,8 +45,35 @@
4045
}
4146
4247
let sidebarEl: HTMLElement | undefined = $state();
48+
49+
$effect(() => {
50+
if (isDesktop.current || !mobileOpen || !sidebarEl) return;
51+
sidebarEl.focus();
52+
});
53+
54+
function handleWindowKeydown(event: KeyboardEvent) {
55+
if (isDesktop.current || !mobileOpen) return;
56+
57+
if (event.key === 'Escape') {
58+
event.preventDefault();
59+
mobileOpen = false;
60+
}
61+
}
62+
63+
// Tabbing off either end of the open panel would land on the page behind the
64+
// backdrop, so send focus back to the top of the panel instead.
65+
function handleFocusOut(event: FocusEvent) {
66+
if (isDesktop.current || !mobileOpen) return;
67+
68+
const next = event.relatedTarget as Node | null;
69+
if (next && sidebarEl?.contains(next)) return;
70+
71+
sidebarEl?.focus();
72+
}
4373
</script>
4474

75+
<svelte:window onkeydown={handleWindowKeydown} />
76+
4577
{#snippet navIcon(IconComponent: Component)}
4678
<IconComponent class="h-5 w-5 shrink-0" aria-hidden="true" />
4779
{/snippet}
@@ -59,8 +91,11 @@
5991
<!-- Sidebar -->
6092
<aside
6193
bind:this={sidebarEl}
94+
onfocusout={handleFocusOut}
6295
id="sidebar"
6396
aria-label={m.sidebar_label()}
97+
tabindex="-1"
98+
inert={hiddenFromUser}
6499
class="border-base-300 bg-base-200 fixed inset-y-0 left-0 z-50 flex flex-col border-r
65100
transition-[transform,width] duration-200 ease-out
66101
lg:relative lg:inset-auto lg:z-auto lg:translate-x-0

0 commit comments

Comments
 (0)