Skip to content

fix(guest-list): wrap Button in li and add role=tab with aria-selected to event tabs - #244

Draft
dccakes wants to merge 1 commit into
mainfrom
claude/sharp-feynman-rse5ll
Draft

dccakes wants to merge 1 commit into
mainfrom
claude/sharp-feynman-rse5ll

Conversation

@dccakes

@dccakes dccakes commented Aug 9, 2026

Copy link
Copy Markdown
Owner

$(cat <<'EOF'

Daily Product Improvement

📝 TLDR

Fix invalid HTML and add ARIA tab roles in the guest-list event tabs component.

📝 Description

The EventsTabs component in the guest list rendered a <Button> as a direct child of the <ul> element. Only <li> elements are permitted as direct children of <ul> — this is an HTML validity violation that some browsers and assistive technologies handle unpredictably.

At the same time, the tab links had no ARIA semantics: screen readers announced them as plain links in a list rather than as interactive tab controls.

This Change

  • Wraps the + New Event <Button> in a <li> element to restore valid HTML structure
  • Moves role="tab" and aria-selected onto the <Link> elements (the actual interactive controls) so assistive technologies correctly identify the tab navigation
  • Moves the styling classes from <li> to the <Link> (adding block display) so visual behavior is unchanged
  • Simplifies the events.map() callback from a block return to an implicit return

No visual change is produced. The fix is structural and semantic only.

Recommendations Reviewed

Area: guest-list/event-tabs.tsx
Issue: <Button> is a direct child of <ul> — invalid HTML. Tab links have no role="tab" or aria-selected.
Recommendation: Wrap Button in <li>, add tab ARIA roles to Link elements.
Type: Frontend cleanup + UX/Accessibility
Priority: High
Effort: Small


Area: vendors/page.tsx
Issue: Any API error (including network timeouts) causes a silent redirect to /.
Recommendation: Redirect only on auth/access errors; show an error state for other failures.
Type: Backend/product flow
Priority: High
Effort: Small


Area: guest-form.tsx
Issue: mode: 'onChange' triggers validation on every keystroke, causing "invalid" flashes mid-input.
Recommendation: Switch to mode: 'onBlur' or mode: 'onTouched'.
Type: UX/UI
Priority: Medium
Effort: Small


Area: planning-overview.tsx → MilestonesCard
Issue: When no milestones exist the card renders an empty body with no explanation or CTA.
Recommendation: Add an empty state with a short description of what milestones are.
Type: UX/UI
Priority: Medium
Effort: Small


Area: task-dialog.tsx
Issue: type="date" input shows "Use YYYY-MM-DD" as a validation error, but the native date picker never requires manual format entry.
Recommendation: Reword to "Please select a valid date" or remove the format hint.
Type: UX/UI
Priority: Medium
Effort: Small


Area: dashboard-topbar.tsx
Issue: today string initialises as '' and is set in useEffect, causing a hydration layout shift.
Recommendation: Use suppressHydrationWarning with a server-formatted date, or render a fixed-width placeholder.
Type: UX/UI
Priority: Medium
Effort: Small


Area: sidebar-nav.tsx
Issue: isActive uses pathname.startsWith(href), which could match /events for a hypothetical /events-legacy route.
Recommendation: Guard with pathname === href || pathname.startsWith(href + '/').
Type: Frontend cleanup
Priority: Medium
Effort: Small


Area: guests-view.tsx
Issue: Filtered-empty state ("No households yet") is identical to the zero-guests state, conflating two distinct situations.
Recommendation: Show "No guests match your search" with a clear-filters button when filters are active.
Type: UX/UI
Priority: Medium
Effort: Small–Medium


Area: guests-view.tsx
Issue: Tags are silently truncated to 4 with no +N more indicator.
Recommendation: Add a +N badge when uniqueTagIds.length > 4.
Type: UX/UI
Priority: Low
Effort: Small


Area: vendor-card.tsx
Issue: priceDisplay() is called twice in the same JSX expression (once in the condition, once to render the value).
Recommendation: Capture in a const price = priceDisplay() variable.
Type: Frontend cleanup
Priority: Low
Effort: Tiny

Selected Improvement

Fix event-tabs.tsx: wrap the + New Event Button in a <li> (valid HTML) and add role="tab" + aria-selected to the Link elements (ARIA tab semantics).

Why This Was Selected

This was the highest-priority unfixed issue across both the HTML validity and accessibility dimensions. The <Button> as a direct child of <ul> is a structural HTML violation (WCAG SC 1.3.1 Info and Relationships) and the missing ARIA tab roles mean screen readers cannot navigate the guest list event filter as a tab control. The change is confined to a single 57-line file, produces no visual change, passes all existing tests, and is easy to verify.

Changes Made

  • Added <li> wrapper around the + New Event <Button> element
  • Added role="tab" and aria-selected to each <Link> tab element
  • Moved the border-b-2, py-3, text-sm, and hover/active className from <li> to <Link>, with block added so the anchor fills its list-item container
  • Simplified events.map() from a block-body return to an implicit arrow-function return

Files Changed

  • src/components/guest-list/event-tabs.tsx

Verification

  • Biome lint passes with no new errors or warnings on the changed file
  • TypeScript type check (tsc --noEmit) passes with zero errors
  • Full unit test suite: 2,023 tests across 233 suites — all pass
  • Diff reviewed: only the targeted file changed, no unrelated modifications

Future Recommendations

Recommendation: Redirect only on auth errors in vendors and budget pages; show a proper error state for transient API failures.
Priority: High
Effort: Small
Reason not included: Separate concern from today's accessibility fix; warrants its own targeted PR.
Should become GitHub issue: Yes

Recommendation: Switch guest-form validation to mode: 'onBlur' to eliminate mid-keystroke "invalid" flashes.
Priority: Medium
Effort: Small
Reason not included: Form behaviour change; best reviewed in isolation.
Should become GitHub issue: No

Recommendation: Add empty state to MilestonesCard when no milestones exist.
Priority: Medium
Effort: Small
Reason not included: Dashboard UI change best batched with related dashboard improvements.
Should become GitHub issue: No

Recommendation: Fix isActive greedy prefix match in sidebar-nav.tsx.
Priority: Medium
Effort: Small
Reason not included: Low immediate risk; no known route collision today. Good candidate for a future cleanup PR.
Should become GitHub issue: No

Recommendation: Distinguish filtered-empty from zero-guests empty state in guests-view.tsx.
Priority: Medium
Effort: Small–Medium
Reason not included: Requires copy changes and a clear-filters action; better handled as part of a broader guest-list UX improvement pass.
Should become GitHub issue: Yes

GitHub Issues Created or Proposed

No issues created this run. The two High/Medium candidates (vendor error redirect, guest-list empty-state distinction) are noted under Future Recommendations and should be tracked as issues in the next triage pass.


Generated by Claude Code

…d to event tabs

The + New Event Button was a direct child of the ul element, which is
invalid HTML (only li elements are permitted as direct children). Assistive
technologies and validators flag this as a structure violation.

Additionally, tab links had no ARIA roles — screen readers announced them
as plain links in a list rather than interactive tab controls. Moving
role=tab and aria-selected to the anchor elements (the actual interactive
controls) and consolidating styles onto the Link give screen readers the
correct semantics, while wrapping the Button in an li element restores
valid HTML.

Co-Authored-By: AgenticDiego <noreply@carvallo.io>
@vercel

vercel Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

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

Project Deployment Actions Updated (UTC)
scv Error Error Aug 9, 2026 10:25am

@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Jest Test Coverage

Coverage Summary

Lines Statements Branches Functions
Coverage: 81%
81.71% (35129/42990) 82.92% (3734/4503) 68.04% (1037/1524)

This branch had an error being deployed

1 failed deployment
Preview — 13ba45ea Deployed Aug 9, 2026 by vercel[bot]
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