Where: src/components/layout/navbar.tsx, desktop nav block (the <nav className="hidden items-stretch lg:flex" ...> element, roughly lines 120–161).
What: The "Product" and "Resources" items in the primary nav render as a <button type="button"> inside a wrapper <div onMouseEnter={() => setOpenMenu(item.label)}>. The submenu (with links like Features, Pricing, "How it works", Documentation, Developers, Blog) is opened purely by onMouseEnter on that wrapper div and closed by onMouseLeave on the parent <nav>. The trigger <button> itself has:
- no
onClick handler
- no
onFocus handler
- no
onKeyDown handler
- no
aria-expanded / aria-haspopup attributes
<button
type="button"
className={cn(
'flex items-center border-l border-border px-4 text-sm font-medium uppercase tracking-wide text-foreground/80 transition-colors hover:bg-secondary hover:text-foreground',
openMenu === item.label && 'bg-secondary text-foreground',
)}
>
{item.label}
</button>
Why it's a problem: A keyboard-only user (or a screen-reader user tabbing through the page) who reaches the "Product" or "Resources" button has no way to open the dropdown — pressing Enter/Space does nothing because there's no onClick, and there is no way to trigger a hover state without a pointer. This makes every link inside those two dropdowns (Features, "How it works", Pricing, Documentation, Developers, Blog) completely unreachable from the primary navigation via keyboard — Tab just skips from "Product" straight to "Resources"/"About"/"Contact". Those pages are still reachable via the footer, but the primary nav — the thing sighted mouse users actually use — is a dead end for keyboard navigation.
This also directly contradicts this repo's own documentation. README.md, under "Accessibility and performance", states:
Interactive pieces like the FAQ accordion and the navigation menu are built on accessible primitives with correct keyboard navigation.
The FAQ accordion (built on Radix UI's Accordion primitive, see src/components/ui/accordion.tsx) is fine — but the nav menu is a bespoke implementation with none of the keyboard affordances Radix would have given it.
Repro:
- Load any page at desktop width (≥1024px, the
lg breakpoint).
- Click into the page, then press Tab repeatedly until focus reaches the "Product" button in the header.
- Press Enter or Space.
- Nothing happens — the dropdown never opens, and the links inside it are never reachable by keyboard.
Suggested fix direction: give the trigger <button> an onClick that toggles openMenu, an onFocus that opens it, aria-expanded={openMenu === item.label} and aria-haspopup="true", plus a way to close on blur/Escape (e.g. an onBlur on the wrapping div that checks e.relatedTarget isn't still inside it).
Labels: bug, accessibility
Where:
src/components/layout/navbar.tsx, desktop nav block (the<nav className="hidden items-stretch lg:flex" ...>element, roughly lines 120–161).What: The "Product" and "Resources" items in the primary nav render as a
<button type="button">inside a wrapper<div onMouseEnter={() => setOpenMenu(item.label)}>. The submenu (with links like Features, Pricing, "How it works", Documentation, Developers, Blog) is opened purely byonMouseEnteron that wrapper div and closed byonMouseLeaveon the parent<nav>. The trigger<button>itself has:onClickhandleronFocushandleronKeyDownhandleraria-expanded/aria-haspopupattributesWhy it's a problem: A keyboard-only user (or a screen-reader user tabbing through the page) who reaches the "Product" or "Resources" button has no way to open the dropdown — pressing Enter/Space does nothing because there's no
onClick, and there is no way to trigger a hover state without a pointer. This makes every link inside those two dropdowns (Features, "How it works", Pricing, Documentation, Developers, Blog) completely unreachable from the primary navigation via keyboard — Tab just skips from "Product" straight to "Resources"/"About"/"Contact". Those pages are still reachable via the footer, but the primary nav — the thing sighted mouse users actually use — is a dead end for keyboard navigation.This also directly contradicts this repo's own documentation.
README.md, under "Accessibility and performance", states:The FAQ accordion (built on Radix UI's
Accordionprimitive, seesrc/components/ui/accordion.tsx) is fine — but the nav menu is a bespoke implementation with none of the keyboard affordances Radix would have given it.Repro:
lgbreakpoint).Suggested fix direction: give the trigger
<button>anonClickthat togglesopenMenu, anonFocusthat opens it,aria-expanded={openMenu === item.label}andaria-haspopup="true", plus a way to close on blur/Escape (e.g. anonBluron the wrapping div that checkse.relatedTargetisn't still inside it).Labels: bug, accessibility