Skip to content

Fix root-layout hydration cost, skip-to-content link, and pipeline-board scale/a11y gaps - #303

Merged
chonilius merged 3 commits into
MergeFi:mainfrom
abayomicornelius:fix/layout-a11y-pipeline-223-225-226-227
Aug 24, 2026
Merged

chonilius merged 3 commits into
MergeFi:mainfrom
abayomicornelius:fix/layout-a11y-pipeline-223-225-226-227

Conversation

@abayomicornelius

Copy link
Copy Markdown
Contributor

Summary

Four fast/scoped fixes bundled together, all in the root layout / maintainer dashboard area:

#225 — No skip-to-content link. Navbar renders directly before <main> with no bypass mechanism, so a keyboard/screen-reader user must tab through the full nav (logo, Bounties/Milestones links, Dashboards dropdown, theme toggle, network badge, sign-in controls) on every page load before reaching content. Added a visually-hidden-until-focused skip link (RootLayout) jumping to a new id="main-content" on <main>, satisfying WCAG 2.4.1 "Bypass Blocks".

#223 — RootLayout forces client hydration for static routes. AuthProvider/WalletProvider wrap every route including the fully static homepage, and their mount-time effects (session check, wallet localStorage read) ran synchronously during the initial commit. A full route-group split isn't viable without a larger refactor since Navbar itself needs auth state on every route (including the homepage) for its own sign-in/out UI, so as a scoped fix both effects are now deferred by one tick (setTimeout) so they run after the initial render commits instead of blocking it — the browser can paint and respond to input sooner. Behavior once the deferred check runs is unchanged.

#226 — Pipeline columns have no render cap. PipelineColumn rendered every bounty matching its stage with no limit or virtualization — fine with the current 5-bounty mock dataset, but a busy maintainer's "Open"/"Funded" column could realistically hold hundreds of unvirtualized cards. Capped each column at 8 visible bounties (matching the existing available.slice(0, 4) pattern in ContributorDashboardPage), with a "View all N in Bounty pipeline" link to /issues when a column exceeds the cap.

#227 — Truncated bounty titles have no recovery path. Card titles are line-clamp-2'd with no title attribute, so a long title is silently cut off with no way to read it without navigating away. Added title={b.title} to each card's Link, consistent with how StatCard already exposes tooltips for its own truncated values.

Changes

  • src/app/layout.tsx — skip-to-content link + id="main-content"
  • src/context/AuthContext.tsx, src/context/WalletContext.tsx — defer mount-time hydration work by one tick
  • src/app/dashboard/maintainer/PipelineBoard.tsx — cap + "View all" link, title attribute on cards

Closes

Closes #223
Closes #225
Closes #226
Closes #227

Test plan

  • npx jest src/context/AuthContext.test.tsx src/context/WalletContext.test.tsx src/app/dashboard/maintainer/PipelineBoard.test.tsx — all 13 existing tests pass unmodified
  • npx eslint on all four touched files — clean
  • Manual click-through of skip link + pipeline "View all" link in a running app (not done in this pass — flagging for reviewer)

Navbar renders directly before <main> with no bypass mechanism, so a
keyboard/screen-reader user must tab through the full nav (logo,
Bounties/Milestones links, Dashboards dropdown trigger, theme toggle,
network badge, sign-in controls) on every single page load before
reaching page content. This is the standard WCAG 2.4.1 "Bypass Blocks"
accommodation and was simply missing.

Adds a visually-hidden-until-focused skip link as the first focusable
element in the body, jumping to a new id="main-content" on <main>.
…cal path (closes MergeFi#223)

Both providers wrap every route in RootLayout, including fully static,
anonymous marketing pages like the homepage. Their mount-time
useEffects (AuthProvider's session-hydration check, WalletProvider's
localStorage read for a saved wallet address) ran synchronously as
part of the initial commit, adding to the JS work a visitor pays
before the page is interactive even when that page has no
auth/wallet-dependent content of its own.

A full route-group split (excluding purely static routes from these
providers) isn't viable here without a larger refactor, since Navbar
itself needs auth state on every route, including the homepage, for
its own sign-in/sign-out UI.

As a scoped fix, both effects are now deferred by one tick via
setTimeout so they run after the initial render commits rather than
blocking it, letting the browser paint and become responsive to input
sooner. Behavior is unchanged once the deferred check runs.
…loses MergeFi#226, closes MergeFi#227)

PipelineColumn rendered every bounty matching its stage with no limit
or virtualization. With the current 5-bounty mock dataset this isn't
observable, but a maintainer managing a busy repo (or several, since
the board isn't scoped to one repo) could see hundreds of bounties in
a single column, each a full DOM subtree, with no cap the way
ContributorDashboardPage already has (available.slice(0, 4)).

Also, each card's title is line-clamped to 2 lines with no way to
recover the full text short of navigating to the bounty's detail page
— no title attribute, no aria-label, and BountyCard elsewhere in the
app doesn't clamp titles at all.

Fixes both by:
- Capping each column at 8 visible bounties, with a "View all N in
  Bounty pipeline" link to /issues when a column has more than that.
- Adding title={b.title} to each card's Link so hovering (or an
  accessible-name lookup) reveals the untruncated title.
@vercel

vercel Bot commented Aug 24, 2026

Copy link
Copy Markdown

@abayomicornelius is attempting to deploy a commit to the chonilius' projects Team on Vercel.

A member of the Team first needs to authorize it.

@chonilius
chonilius merged commit 77bff6d into MergeFi:main Aug 24, 2026
1 of 2 checks passed
@abayomicornelius

Copy link
Copy Markdown
Contributor Author

Superseded by #304 (same fix, raised from a different account). Closing this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment