Skip to content

Commit 0a49e7c

Browse files
Merge pull request #26 from ayushhh101/feat/accessibility-navigation
feat(navigation): improve accessibility and keyboard navigation
2 parents 29b6281 + 4d80c84 commit 0a49e7c

File tree

1 file changed

+35
-9
lines changed

1 file changed

+35
-9
lines changed

src/components/Navigation.jsx

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,35 @@ const Navigation = () => {
4545
}
4646
};
4747

48+
// Keyboard navigation handler for navigation links
49+
const handleKeyDown = (e, idx) => {
50+
if (e.key === "ArrowDown" || e.key === "ArrowRight") {
51+
e.preventDefault();
52+
const next = document.querySelectorAll('[role="menuitem"]')[idx + 1];
53+
if (next) next.focus();
54+
} else if (e.key === "ArrowUp" || e.key === "ArrowLeft") {
55+
e.preventDefault();
56+
const prev = document.querySelectorAll('[role="menuitem"]')[idx - 1];
57+
if (prev) prev.focus();
58+
} else if (e.key === "Home") {
59+
e.preventDefault();
60+
const first = document.querySelectorAll('[role="menuitem"]')[0];
61+
if (first) first.focus();
62+
} else if (e.key === "End") {
63+
e.preventDefault();
64+
const items = document.querySelectorAll('[role="menuitem"]');
65+
if (items.length) items[items.length - 1].focus();
66+
}
67+
};
68+
4869
return (
4970
<>
5071
{/* Mobile Menu Button */}
5172
<div className="lg:hidden fixed top-4 left-4 z-50">
5273
<button
5374
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
54-
className="p-3 bg-white rounded-lg shadow-lg hover:shadow-xl transition-all duration-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
55-
aria-label={isMobileMenuOpen ? 'Close navigation menu' : 'Open navigation menu'}
56-
aria-expanded={isMobileMenuOpen}
75+
className="p-2 bg-white rounded-lg shadow-lg"
76+
aria-label="Open main navigation menu"
5777
>
5878
<div className="w-6 h-6 flex flex-col justify-center space-y-1">
5979
<motion.div
@@ -88,7 +108,7 @@ const Navigation = () => {
88108
transition={{ type: 'spring', damping: 30, stiffness: 300 }}
89109
className="fixed left-0 top-0 h-full w-64 bg-white shadow-xl z-40 lg:z-auto"
90110
role="navigation"
91-
aria-label="Primary"
111+
aria-label="Main Navigation"
92112
>
93113
<div className="p-6 border-b border-gray-200">
94114
<div className="flex items-center space-x-3">
@@ -108,18 +128,22 @@ const Navigation = () => {
108128
</div>
109129

110130
<div className="p-4">
111-
<ul className="space-y-2">
112-
{navigationItems.map((item) => (
113-
<li key={item.path}>
131+
<ul className="space-y-2" role="menubar" aria-label="Main menu">
132+
{navigationItems.map((item, idx) => (
133+
<li key={item.path} role="none">
114134
<Link
115135
to={item.path}
116136
onClick={() => setIsMobileMenuOpen(false)}
117-
className={`flex items-center space-x-3 px-4 py-3 rounded-lg transition-all duration-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 ${
137+
className={`flex items-center space-x-3 px-4 py-3 rounded-lg transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 ${
118138
location.pathname === item.path
119139
? 'bg-blue-50 text-blue-700 border-r-2 border-blue-700 shadow-sm'
120140
: 'text-gray-700 hover:bg-gray-50 hover:text-gray-900'
121141
}`}
122-
aria-current={location.pathname === item.path ? 'page' : undefined}
142+
aria-label={item.label + (location.pathname === item.path ? ' (current page)' : '')}
143+
role="menuitem"
144+
tabIndex={0}
145+
aria-current={location.pathname === item.path ? "page" : undefined}
146+
onKeyDown={e => handleKeyDown(e, idx)}
123147
>
124148
<span className="text-xl" aria-hidden="true">{item.icon}</span>
125149
<span className="font-medium">{item.label}</span>
@@ -184,6 +208,8 @@ const Navigation = () => {
184208
exit={{ opacity: 0 }}
185209
onClick={() => setIsMobileMenuOpen(false)}
186210
className="fixed inset-0 bg-black bg-opacity-50 z-30 lg:hidden"
211+
aria-label="Close main navigation menu"
212+
tabIndex={0}
187213
/>
188214
)}
189215
</AnimatePresence>

0 commit comments

Comments
 (0)