Skip to content

fix(reports): make drill-down reachable by keyboard and the page fit a phone - #152

Merged
KenTaniguchi-R merged 1 commit into
mainfrom
fix/147-access-layout
Sep 2, 2026
Merged

fix(reports): make drill-down reachable by keyboard and the page fit a phone#152
KenTaniguchi-R merged 1 commit into
mainfrom
fix/147-access-layout

Conversation

@KenTaniguchi-R

Copy link
Copy Markdown
Owner

The access & layout third of #147. Charts (PR B) and information design (PR C) follow separately, each with a mock first.

Stacked on #151#150. GitHub retargets as those merge. The diff below is only this change.

Drill-down was mouse-only

Every target measured tabIndex: -1 with no role — 18 table rows, 9 legend entries, and the Sankey nodes. Spending table rows, the Income vs Expense table, the donut legend and the Sankey rects now take focus, announce what they do (Show Groceries transactions, $1,891.26), and activate on Enter or Space via a shared activateOnKey. A target with nothing to activate returns no handler, so it stays out of the tab order instead of becoming an empty stop.

The donut's own sectors remain mouse-only — Recharts sectors cannot hold focus — but the legend beside them offers the same targets, so nothing is reachable only by mouse.

The page overflowed sideways

At 555px client width, scrollWidth was 569. Two causes:

The tablist. It computes overflow-x: visible, so instead of scrolling it widened the page, and Trends and Net Worth sat off-screen with no affordance to reach them. Now in a scroll container. (Fixed locally rather than in tabsListVariants, which every tab list in the app shares.)

The summary bar. report-summary-bar.tsx set gridTemplateColumns: repeat(n, 1fr) as an inline style, which no breakpoint can reach — a phone kept the desktop column count and clipped the third tile to its icon. Grid classes now, one column on a phone. Each tile also gets min-w-0, so 1fr stops yielding to a long label: tiles measured 173 / 133 / 180px and are now equal.

Stray scrollbar on the donut legend

overflow-y-auto alone makes CSS compute overflow-x: auto, and scrollWidth 306 > clientWidth 302 was enough to paint one. Pinned to overflow-x-hidden.

FAB clearance

The AI assistant button is fixed bottom-6 right-6 and floats over whatever the page ends with, so <main> now reserves its height. This clears content at rest. A fixed button still passes over content mid-scroll — inherent to the pattern, and moving or fading it is a design decision, so it goes to PR B/C with a mock rather than being decided here.

One claim in #147 is not a bug

the sidebar avatar and the AI assistant FAB sit on top of page content on every tab

The element over the sidebar is NEXTJS-PORTAL — the Next.js dev-tools indicator, which ships in no build. Confirmed with document.elementFromPoint. The FAB half is real and handled above.

Tests

src/lib/a11y.test.ts — 4 unit tests on activateOnKey: returns nothing without an action (so the element stays untabbable), Enter and Space activate and call preventDefault (Space would otherwise scroll), and every other key including Spacebar is left alone.

Colocated unit suite: 698 passed across 75 files.

Verification

Measured live at 390px and 1440px:

before after
page scrollWidth / clientWidth 569 / 555 555 / 555
tablist wrapper overflow-x visible auto (561 scrollable in 531)
table row tabIndex -1, no role tabIndex 0, role=button, labelled
legend row tabIndex -1, no role tabIndex 0, role=button, labelled
legend overflow-x auto, 306 > 302 hidden
summary tiles 173 / 134 / 185px equal

Focusing a table row, a legend entry and a Sankey node and pressing Enter each opened the correct drill-down sheet.

🤖 Generated with Claude Code

…a phone

The access and layout half of #147. Charts and information design follow
separately.

Every drill-down target measured `tabIndex: -1` with no role — 18 table
rows, 9 legend entries and the Sankey nodes. Drill-down was mouse-only.
Table rows, the donut legend and the Sankey rects now take focus, announce
what they do, and activate on Enter or Space through a shared
`activateOnKey`. A target with nothing to activate stays out of the tab
order rather than becoming an empty stop. The donut's own sectors are still
mouse-only — Recharts sectors cannot hold focus — but the legend beside them
offers the same targets, so nothing is now reachable only by mouse.

At 555px the page overflowed to 569 and scrolled sideways. Two causes. The
tablist computes `overflow-x: visible` and simply widened the page, leaving
Trends and Net Worth off-screen with no scroll affordance; it sits in a
scroll container now. And `report-summary-bar` set `gridTemplateColumns` as
an inline style, which no breakpoint can reach, so a phone kept the desktop
column count and clipped the third tile to its icon; it is grid classes now,
one column on a phone, and each tile is `min-w-0` so `1fr` stops yielding to
a long label (the tiles measured 173 / 133 / 180 rather than equal thirds).

The donut legend painted a stray horizontal scrollbar — `overflow-y-auto`
alone makes CSS compute `overflow-x: auto`, and 306 > 302 was enough to show
one. Pinned to `overflow-x-hidden`.

The AI assistant button is `fixed bottom-6 right-6` and floats over whatever
the page ends with, so `<main>` reserves its height. This clears content at
rest; a fixed button still passes over content mid-scroll, which is inherent
to the pattern and a design question rather than a layout bug.

Not changed: #147 also reports the sidebar avatar overlapping page content.
That element is `NEXTJS-PORTAL`, the dev-tools indicator, which ships in no
build — there is no product bug there.

Verified at 390px and 1440px: page scrollWidth now equals clientWidth, the
tablist scrolls, summary tiles are equal width, and focusing a table row, a
legend entry or a Sankey node and pressing Enter opens the drill-down.

Refs #147
@KenTaniguchi-R
KenTaniguchi-R changed the base branch from fix/145-cash-flow-tiles to main September 2, 2026 13:02
@KenTaniguchi-R
KenTaniguchi-R merged commit dd72b3f into main Sep 2, 2026
5 checks passed
@KenTaniguchi-R
KenTaniguchi-R deleted the fix/147-access-layout branch September 2, 2026 13:10
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