Rebuilt curl.se's site-wide navigation after identifying that its hover-dependent interaction model was reliably usable only with a mouse, leaving keyboard, touch, and screen-reader users without dependable access to nested navigation.
Introduced proper accessibility semantics and a consistent interaction model across mouse, keyboard, touch, and assistive technology using native browser controls, without JavaScript or new dependencies.
Implemented the system inside curl.se's long-lived custom Make, FCPP, and Perl toolchain, consolidating eight menu variants behind shared templates and adding build-time validation.
Shipped upstream as five commits on curl-www master, applied directly by curl founder Daniel Stenberg with Rito's authorship preserved on each one.
Why curl.se Matters:
curl is both a command-line data-transfer tool and libcurl, a portable networking library embedded throughout modern software and hardware. The curl project estimates libcurl runs across more than 20 billion installations, in phones, routers, televisions, vehicles, medical devices, and games. The website is not that library, but it inherits its audience: curl.se is where those developers go to read the manual, check a vulnerability, or learn how to contribute.
It houses the curl manual, libcurl API documentation, protocol references, release and vulnerability information, build instructions, and contribution resources. Its navigation provides access to a large, technically dense body of information used by everyone from first-time command-line users to experienced libcurl contributors.
A Navigation System That Only Worked Reliably With A Mouse:
The original navigation depended on CSS hover to reveal nested links. That made it reasonably usable with a conventional desktop mouse, but hover was not merely a visual enhancement. It controlled whether major areas of the website could be accessed at all.
Keyboard users could focus top-level links without reliably opening their submenus. Desktop screen-reader users relying on keyboard navigation inherited the same failure. On touchscreens, tapping could follow a category link instead of revealing its submenu, while long-pressing could open the browser's context menu. The exact behavior varied across browsers and devices, making the navigation inconsistent and unpredictable.
Before: long-pressing a category on mobile
Long-pressing a category on curl.se: the submenu begins to open, but the browser's own context menu covers it, leaving the nested links unreachable.
The underlying problem was a lack of proper accessibility semantics. The categories looked like menu controls to mouse users, but the browser did not understand them as native controls with a meaningful open or closed state. Keyboard users, touch users, and assistive technologies therefore did not receive the same dependable interaction model.
The problem was not that hover needed improvement. The problem was that hover determined whether navigation was available.
An Unusually Old And Constrained Website System:
curl.se is not built with a contemporary web framework or modern component system. It uses a long-lived custom static-site setup driven by GNU Make, FCPP macros that behave like a C-preprocessor-based template system, and Perl scripts for build and validation tasks.
There was no React component, application state layer, or modern navigation library available to replace the old behavior. Navigation markup existed across eight page-specific menu variants and had to continue working within the project's established generation process.
The replacement also needed to add no JavaScript and no new dependencies. That removed the standard modern tools for dropdown state, mobile-menu state, click-outside dismissal, focus behavior, and responsive interaction. The available technical toolbox was extremely narrow, but the behavioral target was expansive: one coherent system across mouse, keyboard, touch, assistive technology, mobile, desktop, multiple browsers, and eight generated menu variants.
Designing A Cross-Input System With Native Browser Controls:
Rito replaced hover-controlled availability with native HTML disclosure controls. The browser could now understand each category as an operable control with meaningful state, providing a shared interaction foundation rather than a separate workaround for every input method.
Native Accessibility Semantics
Used native <details> and <summary> controls so categories could be opened consistently by mouse, keyboard, and touch, while visible focus states and current-page labeling improved orientation for assistive-technology users.
Hover As Enhancement, Not Access
Native disclosure state became the dependable source of access. Desktop hover could later return as an optional preview, but no destination depended on it and keyboard or touch users remained on the native interaction path.
Preserving Existing Destinations
Category labels had previously linked to overview pages. Converting them into controls could have removed those destinations, so each submenu received an overview link as its first item.
No-JavaScript Mobile Navigation
Built an entirely new mobile experience where none had existed: a labeled, keyboard-operable toggle and a viewport-bounded, independently scrollable menu, with every control meeting the 44-pixel touch-target minimum. No JavaScript, no new dependencies, and no page-wide horizontal overflow.
Mobile navigation, before and after
&
Before
After
After: using the rebuilt mobile menu
Menu Open
Tapping the toggle opens a viewport-bounded, independently scrollable menu listing every top-level category. The control reports its own state, switching from a hamburger to a close icon.
Submenu Expanded
Opening a category reveals its nested links on tap alone, with no long-press and no context menu. "Download overview" leads the list, preserving the destination the category label used to point to.
After: keyboard and mouse navigation on desktop
Tabbing through curl.se on desktop: each category opens its submenu on focus, and focus then moves into the nested links themselves, so every destination is reachable without a mouse. The final pass shows hover still revealing the same submenu, a preview layered on top of the native behavior rather than the means of access.
Making The Legacy System Safer:
curl.se did not have one navigation. It had eight. The main site menu and the section menus for dev, docs, libcurl, libcurl/c, libcurl/using, trurl, and wcurl each carried their own hand-maintained copy of the same structure. Changing how navigation worked meant editing eight files, keeping them consistent by eye, and discovering any missed variant only when someone browsing that section of the site noticed.
Rather than rewrite eight menus independently and leave them to drift again, Rito introduced shared FCPP macros that generate consistent semantic markup from a single definition while preserving each section's information architecture. Shared Make dependencies rebuild every dependent page when the common templates change. A navigation change now happens once, and no variant can silently fall behind the others.
Generating markup from macros introduces its own failure modes, so the enforcement shipped alongside the abstraction rather than after it. Rito added a dedicated Perl validator, exposed through the existing Make workflow and run in CI, that inspects the generated pages for duplicate controls, malformed disclosure structures, invalid initial state, empty menus, and template tokens that leaked into the finished HTML.
After: one definition, eight generated menus
Eight hand-maintained menus became one definition with a build-enforced gate: no variant can silently fall behind, and malformed navigation cannot reach production.
The result was not only a more accessible navigation. It was a system in which the previous failure could not quietly happen again.
Stewarding The System Through Maintainer Review:
The initial direction received immediate validation from curl founder and lead maintainer Daniel Stenberg, who reviewed the initial implementation and said, "I think this is a fine improvement."
That endorsement validated the core concept, but several difficult interaction details remained. Review ran across two weeks and drew in multiple curl maintainers and collaborators, covering interaction model, keyboard behavior across browsers, mobile behavior, visual presentation, and implementation complexity. Project participants asked for click-outside dismissal, familiar desktop hover behavior, and clearer visual feedback. Each request had to be implemented without undermining the accessibility foundation or introducing JavaScript.
Click-Outside Dismissal Without JavaScript
A reviewer suggested a transparent page layer, but the initial approach would have forced two clicks to switch menus. Rito found a layered variation that sits behind the controls and open panel, allowing outside-click dismissal while preserving one-click menu switching on desktop and mobile.
Familiar Hover, Accessible State
Maintainers wanted the speed of the old desktop hover behavior. Rito restored it as an optional CSS-only preview while keeping native disclosure state responsible for committed access through click, keyboard, touch, and assistive technology.
Explaining The Semantic Trade-Off
A CSS-only hover preview can make a submenu visible while the browser still considers its native control closed. Rito documented that temporary visual and semantic mismatch, limited it to deliberate pointer hover, suppressed previews during explicit open state, and kept the hover work removable as a separate commit.
Conceding On Evidence, Not On Volume
A reviewer asked for twenty percent less whitespace between menu rows, since the Documentation menu had grown long enough to scroll. What read as whitespace was actually the touch targets: each row was sized to at least 44 by 44 CSS pixels, so the space around every label was the tap area itself. Rito shrank the targets on desktop, where a mouse pointer is precise and target size matters less, and held 44 pixels on mobile, citing WCAG 2.2's Level AAA Target Size (Enhanced) criterion, which protects people pressing controls with fingers or with limited dexterity. The concession was genuine, and it stopped where the accessibility rationale began.
The stewardship mattered as much as the initial implementation. Rito did not simply bolt reviewer requests onto the navigation. He incorporated them into a coherent model that reconciled semantic accessibility, familiar mouse efficiency, no-JavaScript constraints, and the behavior of the existing legacy system.
Late requests to drop the sticky header, restore the previous menu height, and remove the chevron indicators were implemented the same day they were raised. Those were questions of presentation, and Rito treated them as such. Knowing which requests to absorb quickly and which to answer with a standard is what kept a two-week review moving toward a result instead of stalling in it.
The review closed with agreement from every participant. Reviewers signed off with "This is looking really good now" and "Looking good, thanks a lot for the updates and the PR!" Stenberg landed the work himself, closing with "Thanks a lot! This PR has now been merged and should get visible on the site." All five commits were applied to curl-www master with Rito's authorship preserved on each one.
Testing Across Inputs And Browsers:
Because the original failure varied by device, browser, and input method, visual comparison was not enough. Rito tested desktop and mobile versions of Chrome, Firefox, and Edge using mouse, keyboard, and touch. Testing covered forward and reverse focus traversal, submenu interaction, menu scrolling, touch-target sizing, and narrow-width overflow.
The site build, existing Perl checks, and new navigation validator were also run together so the interaction design was supported by generated-output validation rather than manual inspection alone.
Outcome:
The system shipped to curl.se, replacing hover-dependent navigation with an interaction architecture that supports mouse, keyboard, touch, and assistive technology without JavaScript or new dependencies. On desktop, the visible design stayed deliberately close to what curl users already knew: the accessibility layer, expandable menus, and overview destinations went in, optional hover convenience returned, and open menus gained outside-click dismissal. On mobile, the site gained a navigation experience it had never had.
Beneath the visible interface, it consolidated eight menu variants behind shared generation primitives and added automated validation for the generated site.
Implementation And Review Evidence:
The work landed as five commits on curl-www master, authored by Rito and committed by Daniel Stenberg.