Skip to content

fix(nav): the shared chrome shipped two defects no consumer could fix - #8

Merged
catomean merged 1 commit into
mainfrom
fix/nav-target-and-focus
Aug 31, 2026
Merged

fix(nav): the shared chrome shipped two defects no consumer could fix#8
catomean merged 1 commit into
mainfrom
fix/nav-target-and-focus

Conversation

@catomean

Copy link
Copy Markdown
Contributor

A shared renderer is the one place where a mistake is not one bug in one repo but the same bug on every site that installs it — and unfixable downstream, because a consumer cannot patch markup it does not own. Two shipped.

The defects

1. Nav links were ~28px targets. px-2 py-1 on text-xs is a fiddly thing to hit on a phone, and below the 44px floor the rest of the fleet holds (fleetcrown enforces it centrally via a @media (pointer: coarse) block; kivvi and wild-spirit set it explicitly). Now inline-flex min-h-11 items-center.

2. The package defined no focus style at all. A consumer's CSS reset can remove the user-agent ring, and nothing here replaced it — so keyboard users could lose their visible position in the nav on every site that installs this. Both the nav links and the wordmark now carry focus-visible:outline-2 outline-offset-2 outline-accent, a semantic class so the colour stays the consumer's, per this package's no-tokens rule.

The masthead does not get taller

Its own comment warns that wrapping the nav "makes a sticky masthead eat a third of a phone screen." So the row pays for the bigger targets out of its own padding: py-4py-2, and 44px items land the header at the height it already had. There's a test asserting exactly that, so nobody re-inflates it later.

Tests

Five rendered tests — asserting markup, not source, and importing by package name so a broken exports map fails here rather than in a consumer. Four fail against the previous renderers. The fifth covers aria-current, which already worked; it's guarded so a refactor of these classes can't quietly drop it.

npm run verify green: lint, typecheck, build, 33 tests.

Release

Version bumped 0.2.0 → 0.3.0 (README install line updated to match). Both live consumers inherit these defects today and are also drifted from each other — substrata on v0.1.1, camille-boulangerie on v0.2.0 — so both should move to v0.3.0. I'll open those bumps once this lands.

One incidental note

.gitignore has node_modules/ with a trailing slash, which matches a directory but not a symlink. Anyone working in a git worktree who symlinks node_modules will find it staged by git add -A. Not fixed here to keep this PR to one subject, but worth a one-character change.

Found by a fleet-wide navigation audit across 20 repos, where this was the only defect that multiplies.

🤖 Generated with Claude Code

https://claude.ai/code/session_01XeELB8b3N4JrT2asYL9WvE

A shared renderer is the one place where a mistake is not one bug in one repo
but the same bug on every site that installs it — and unfixable downstream,
because a consumer cannot patch markup it does not own. Two shipped:

1. Nav links were `px-2 py-1` on `text-xs`, roughly a 28px target. That is a
   fiddly thing to hit on a phone and below the 44px floor the rest of the
   fleet holds (fleetcrown enforces it centrally; kivvi and wild-spirit meet
   it explicitly). Now `inline-flex min-h-11 items-center`.

2. The package defined no focus style at all. A consumer's CSS reset can
   remove the user-agent ring, and nothing here replaced it, so keyboard
   users could lose their visible position in the nav on every site that
   installs this. Both the nav links and the wordmark now carry
   `focus-visible:outline-2 outline-offset-2 outline-accent` — a semantic
   class, so it stays the consumer's colour, per this package's no-tokens rule.

The masthead does NOT get taller. Its own comment warns that wrapping the nav
"makes a sticky masthead eat a third of a phone screen", so the row pays for
the bigger targets out of its own padding: py-4 becomes py-2, and 44px items
land the header at the height it already had.

Five rendered tests, asserting markup rather than source and importing by
package name so a broken exports map fails here rather than in a consumer.
Four fail against the previous renderers; the fifth covers `aria-current`,
which already worked and is guarded so a refactor of these classes cannot
quietly drop it.

Both live consumers inherit this: substrata (v0.1.1) and camille-boulangerie
(v0.2.0) are also version-drifted from each other, so both move to v0.3.0.

Found by a fleet-wide navigation audit across 20 repos, where this was the
only defect that multiplies.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XeELB8b3N4JrT2asYL9WvE
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant