-
Notifications
You must be signed in to change notification settings - Fork 0
🎨 Palette: [UX improvement] Add ARIA labels and focus states to Navbar #135
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
84d2563
dfe4a2d
1a5b3ef
dac1bd0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
|
|
||
| ## 2024-03-23 - [Adding Keyboard Focus Rings to Custom Components] | ||
| **Learning:** Custom components like `motion.button` and pure visual elements (like styled `div` wrappers) easily lose their keyboard navigability when stripped of native HTML button semantics. In `Navbar.tsx`, interactive icons and visually simulated buttons lacked the `focus-visible` ring. | ||
| **Action:** When working on navigation or custom component libraries in this app, explicitly use `focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:outline-none` on interactive elements to ensure they do not become "dead ends" for keyboard users, and convert interactive `div` wrappers into native `<button>` tags so they can receive tab focus naturally. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,6 @@ | ||
| packages: | ||
| - '.' | ||
|
|
||
| onlyBuiltDependencies: | ||
| - '@firebase/util' | ||
| - '@prisma/engines' | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -32,17 +32,20 @@ export default function Navbar() { | |||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| <div className="flex items-center gap-8"> | ||||||||||||||||||||||||||||||||||
| <div className="hidden md:flex items-center gap-3 px-4 py-2 rounded-full bg-white/5 border border-white/5 text-slate-400 hover:text-white hover:bg-white/10 transition-all cursor-pointer group"> | ||||||||||||||||||||||||||||||||||
| <button | ||||||||||||||||||||||||||||||||||
| aria-label="Search Commands" | ||||||||||||||||||||||||||||||||||
| className="hidden md:flex items-center gap-3 px-4 py-2 rounded-full bg-white/5 border border-white/5 text-slate-400 hover:text-white hover:bg-white/10 transition-all cursor-pointer group focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:outline-none" | ||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||
| <Search className="w-4 h-4 group-hover:scale-110 transition-transform" /> | ||||||||||||||||||||||||||||||||||
| <span className="text-xs font-bold tracking-wider">SEARCH COMMANDS</span> | ||||||||||||||||||||||||||||||||||
| <span className="text-[10px] bg-white/10 px-1.5 py-0.5 rounded border border-white/10 font-mono">⌘K</span> | ||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
| </button> | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| <div className="flex items-center gap-4"> | ||||||||||||||||||||||||||||||||||
| <IconButton icon={<Bell className="w-5 h-5" />} /> | ||||||||||||||||||||||||||||||||||
| <IconButton icon={<User className="w-5 h-5" />} /> | ||||||||||||||||||||||||||||||||||
| <IconButton icon={<Bell className="w-5 h-5" />} ariaLabel="Notifications" /> | ||||||||||||||||||||||||||||||||||
| <IconButton icon={<User className="w-5 h-5" />} ariaLabel="User Profile" /> | ||||||||||||||||||||||||||||||||||
| <div className="h-8 w-[1px] bg-white/10 mx-2" /> | ||||||||||||||||||||||||||||||||||
| <div className="flex items-center gap-3 px-4 py-2 rounded-xl bg-emerald-500/10 border border-emerald-500/20 group cursor-pointer"> | ||||||||||||||||||||||||||||||||||
| <div className="flex items-center gap-3 px-4 py-2 rounded-xl bg-emerald-500/10 border border-emerald-500/20 group cursor-pointer" title="System Status: Online" aria-label="System Status: Online"> | ||||||||||||||||||||||||||||||||||
| <div className="w-2 h-2 rounded-full bg-emerald-500 animate-pulse shadow-[0_0_10px_rgba(16,185,129,0.5)]" /> | ||||||||||||||||||||||||||||||||||
| <span className="text-[10px] font-black text-emerald-500 tracking-widest uppercase">System Online</span> | ||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+48
to
51
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Potential accessibility inconsistency: interactive-looking element is not keyboard accessible. This If this element is intended to be interactive (e.g., clicking opens a status panel), convert it to a 💡 Option A: If interactive, convert to button- <div className="flex items-center gap-3 px-4 py-2 rounded-xl bg-emerald-500/10 border border-emerald-500/20 group cursor-pointer" title="System Status: Online" aria-label="System Status: Online">
+ <button type="button" className="flex items-center gap-3 px-4 py-2 rounded-xl bg-emerald-500/10 border border-emerald-500/20 group focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:outline-none" title="System Status: Online" aria-label="System Status: Online">
<div className="w-2 h-2 rounded-full bg-emerald-500 animate-pulse shadow-[0_0_10px_rgba(16,185,129,0.5)]" />
<span className="text-[10px] font-black text-emerald-500 tracking-widest uppercase">System Online</span>
- </div>
+ </button>💡 Option B: If non-interactive, remove cursor-pointer- <div className="flex items-center gap-3 px-4 py-2 rounded-xl bg-emerald-500/10 border border-emerald-500/20 group cursor-pointer" title="System Status: Online" aria-label="System Status: Online">
+ <div className="flex items-center gap-3 px-4 py-2 rounded-xl bg-emerald-500/10 border border-emerald-500/20 group" title="System Status: Online" aria-label="System Status: Online">📝 Committable suggestion
Suggested change
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||
|
|
@@ -55,19 +58,21 @@ export default function Navbar() { | |||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| function NavLink({ href, label }: { href: string, label: string }) { | ||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||
| <Link href={href} className="text-xs font-black text-slate-400 hover:text-white tracking-widest uppercase transition-colors relative group"> | ||||||||||||||||||||||||||||||||||
| <Link href={href} className="text-xs font-black text-slate-400 hover:text-white tracking-widest uppercase transition-colors relative group focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:outline-none focus-visible:rounded"> | ||||||||||||||||||||||||||||||||||
| {label} | ||||||||||||||||||||||||||||||||||
| <span className="absolute -bottom-2 left-0 w-0 h-[2px] bg-indigo-500 group-hover:w-full transition-all duration-300" /> | ||||||||||||||||||||||||||||||||||
| </Link> | ||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| function IconButton({ icon }: { icon: React.ReactNode }) { | ||||||||||||||||||||||||||||||||||
| function IconButton({ icon, ariaLabel }: { icon: React.ReactNode, ariaLabel: string }) { | ||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||
| <motion.button | ||||||||||||||||||||||||||||||||||
| whileHover={{ scale: 1.1, y: -2 }} | ||||||||||||||||||||||||||||||||||
| whileTap={{ scale: 0.9 }} | ||||||||||||||||||||||||||||||||||
| className="p-2.5 rounded-xl bg-white/5 border border-white/5 text-slate-400 hover:text-white hover:bg-white/10 transition-all" | ||||||||||||||||||||||||||||||||||
| aria-label={ariaLabel} | ||||||||||||||||||||||||||||||||||
| title={ariaLabel} | ||||||||||||||||||||||||||||||||||
| className="p-2.5 rounded-xl bg-white/5 border border-white/5 text-slate-400 hover:text-white hover:bg-white/10 transition-all focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:outline-none" | ||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||
| {icon} | ||||||||||||||||||||||||||||||||||
| </motion.button> | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Date appears incorrect.
The entry is dated
2024-03-23, but based on the PR creation date, this should likely be2026-03-23.📝 Proposed fix
📝 Committable suggestion
🤖 Prompt for AI Agents