Skip to content

Fix ARIA ID uniqueness in HistoryView#17

Merged
auerbachb merged 5 commits into
mainfrom
issue-16-aria-id-uniqueness
Feb 27, 2026
Merged

Fix ARIA ID uniqueness in HistoryView#17
auerbachb merged 5 commits into
mainfrom
issue-16-aria-id-uniqueness

Conversation

@auerbachb
Copy link
Copy Markdown
Owner

@auerbachb auerbachb commented Feb 27, 2026

Summary

  • Adds array index to id and aria-controls attributes in HistoryView expanded thought panels
  • Prevents duplicate HTML IDs when multiple sessions share the same dayNumber (e.g., abandoned + retried)

Closes #16

Test plan

  • aria-controls uses day-${entry.day}-${idx}-thoughts pattern
  • id uses matching day-${entry.day}-${idx}-thoughts pattern
  • npm run build passes without errors

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Fixed accessibility linking so controls correctly connect to each entry's content.
  • Improvements

    • Expand/collapse now operates per-history-entry with unique entry keys and consistent keyboard interaction.
    • Thoughts are grouped by session and shown only for their associated entry; expansion is enabled only when thoughts exist.
    • Cursor and interactive affordances now reflect expandable state.
    • Thought items in responses now include session association for clearer grouping.
  • Documentation

    • Updated ARIA labels and controls for per-entry panels.

Include array index in id and aria-controls attributes to prevent
duplicate HTML IDs when multiple sessions share the same dayNumber.

Closes #16

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel Bot commented Feb 27, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
still-point Ready Ready Preview, Comment Feb 27, 2026 9:03pm

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 27, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 64d6f0d and f384f99.

📒 Files selected for processing (3)
  • src/app/api/thoughts/route.ts
  • src/components/HistoryView.tsx
  • src/lib/api.ts

📝 Walkthrough

Walkthrough

Adds sessionId to Thought objects (API and client types) and refactors HistoryView to track and render expansion per history entry with unique entryId (day+index). Groups thoughts by sessionId, uses per-entry expansion state, and updates ARIA ids/labels and interaction to be entry-specific.

Changes

Cohort / File(s) Summary
History view — state, IDs, rendering, accessibility
src/components/HistoryView.tsx
Replaced per-day expansion with per-entry expansion using expandedEntryId (string
API route — thoughts payload
src/app/api/thoughts/route.ts
GET response now selects and returns sessionId for each thought record, expanding the emitted thought object shape to include sessionId.
Client types / API typings
src/lib/api.ts
Updated exported Thought type to include required sessionId: string, aligning client typings with the API response shape.

Sequence Diagram(s)

sequenceDiagram
    participant UI as HistoryView (Client)
    participant API as /api/thoughts (Server)
    participant DB as Thoughts DB

    UI->>API: GET /api/thoughts
    API->>DB: query thoughts (select sessionId)
    DB-->>API: thoughts[] (with sessionId)
    API-->>UI: thoughts[] (with sessionId)
    UI->>UI: group thoughts by sessionId (useMemo)
    UI->>UI: build entries with entryId = day + index
    UI->>UI: determine canExpand via getThoughtsForSession(sessionId)
    UI->>UI: toggle expandedEntryId when entry activated (click/Enter/Space)
    Note over UI: Expanded region renders entryThoughts (t.id keys)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

I hop through sessions, stitch day and index tight,
Each thought now bears a session, kept in gentle sight.
No duplicate IDs, ARIA sings along,
I nibble at bugs and whistle a small song. 🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: fixing ARIA ID uniqueness in HistoryView by including array indices to prevent duplicate IDs.
Linked Issues check ✅ Passed The PR addresses issue #16 by adding sessionId tracking and per-entry expansion logic with unique entryId-based identifiers, exceeding the minimum requirement of index-based ARIA IDs.
Out of Scope Changes check ✅ Passed Changes to api.ts and the Thought type add sessionId field to support per-session thought tracking, which is a reasonable extension to fix the root cause of non-unique IDs when multiple sessions share the same day.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch issue-16-aria-id-uniqueness

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/HistoryView.tsx`:
- Around line 211-213: The expansion state is currently keyed only by entry.day
(expandedDay) so multiple entries from the same day toggle together; change to
an entry-scoped key (e.g. create a new state variable expandedEntry and setter
setExpandedEntry) and use a unique key such as `${entry.day}-${idx}` or the
entry's stable id instead of entry.day; update the aria-expanded checks and
onClick handlers (replace expandedDay with expandedEntry and setExpandedDay(...)
with setExpandedEntry(...) using the same unique key) so each entry
expands/collapses independently and preserves unique region labeling.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 64d6f0d and e8679f3.

📒 Files selected for processing (1)
  • src/components/HistoryView.tsx

Comment thread src/components/HistoryView.tsx Outdated
Switch expandedDay (keyed by dayNumber) to expandedEntryId (keyed by
day-idx composite) so duplicate-day entries expand independently.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/HistoryView.tsx`:
- Around line 216-218: The aria-expanded state is being set to true even when no
region is rendered (entryThoughts.length === 0), causing an accessibility
mismatch; update the logic around aria-expanded and the click handler (where
setExpandedEntryId is used) to consider a hasThoughts boolean (e.g., const
hasThoughts = entryThoughts.length > 0) and only set aria-expanded to true when
isExpanded && hasThoughts, and prevent toggling expansion when hasThoughts is
false (or alternatively disable the toggle UI) in the onClick; apply the same
change where aria-expanded and setExpandedEntryId are used (including the other
occurrences mentioned).
- Around line 88-89: getThoughtsForDay currently filters only by day
(thoughts.filter(t => t.dayNumber === day)), which merges thoughts across
sessions and causes duplicate/misaligned panels; change the logic to scope
thoughts to the specific entry's session by filtering on both dayNumber and
sessionId (e.g., add an argument or create getThoughtsForEntry that uses
entry.sessionId and entry.day), and update all call sites that use
getThoughtsForDay (places referencing entry.day/entry.thoughtCount and any other
usages) so the returned list matches entry.thoughtCount and is limited to the
same session.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e8679f3 and 3072587.

📒 Files selected for processing (1)
  • src/components/HistoryView.tsx

Comment thread src/components/HistoryView.tsx Outdated
Comment thread src/components/HistoryView.tsx Outdated
- Return sessionId from /api/thoughts endpoint
- Add sessionId to Thought type in api.ts
- Filter thoughts per session (not per day) to prevent cross-session merging
- Add canExpand guard: only set aria-expanded/aria-controls when thoughts exist
- Prevent click/keydown expansion on entries with no captured thoughts

Addresses CR review round 2 findings on PR #17.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/HistoryView.tsx`:
- Around line 90-92: The current getThoughtsForSession function causes a full
scan of thoughts for every row render; refactor inside the HistoryView component
to pre-group thoughts by sessionId once (e.g., build a Map or object keyed by
sessionId) using useMemo with thoughts as the dependency, then replace
getThoughtsForSession to simply lookup the grouped map by sessionId (returning
[] if missing); ensure symbols referenced are getThoughtsForSession, thoughts,
sessionId and that the grouping memoization lives in the same component so
renders reuse the precomputed groups.
- Around line 217-220: The row currently sets role="button" and tabIndex={0}
regardless of canExpand, causing a non-actionable focusable element; update the
JSX in HistoryView (the element using canExpand, entryId, isExpanded) so role
and tabIndex are only added when canExpand is true (e.g., role={canExpand ?
"button" : undefined} and tabIndex={canExpand ? 0 : undefined}), keeping
aria-expanded and aria-controls behavior as-is.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3072587 and c813fac.

📒 Files selected for processing (3)
  • src/app/api/thoughts/route.ts
  • src/components/HistoryView.tsx
  • src/lib/api.ts

Comment thread src/components/HistoryView.tsx
Comment thread src/components/HistoryView.tsx Outdated
- Pre-group thoughts by sessionId with useMemo to avoid per-row filter scans
- Only set role="button" and tabIndex={0} when canExpand is true
- Non-expandable rows no longer receive focus or button semantics

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/HistoryView.tsx`:
- Around line 319-320: The list rendering inside entryThoughts.map uses the
array index as the React key (key={i}) which can cause incorrect DOM reuse;
change the key to the stable Thought id (use t.id from the mapped item) in the
map callback where entryThoughts.map((t, i) => ...) and ensure the mapped
element uses that id as its key instead of i to provide stable identity for each
Thought.

ℹ️ Review info

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c813fac and bfed219.

📒 Files selected for processing (1)
  • src/components/HistoryView.tsx

Comment thread src/components/HistoryView.tsx Outdated
Replace array index keys with t.id for stable DOM identity
in the expanded thoughts panel.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@auerbachb
Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 27, 2026

✅ Actions performed

Full review triggered.

@auerbachb
Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 27, 2026

✅ Actions performed

Full review triggered.

@auerbachb auerbachb merged commit 352d4e6 into main Feb 27, 2026
3 checks passed
@auerbachb auerbachb deleted the issue-16-aria-id-uniqueness branch February 27, 2026 22:20
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.

HistoryView: ARIA IDs not guaranteed unique when duplicate dayNumbers exist

1 participant