Skip to content

fix(dashboard): replace div with main landmark for screen reader accessibility - #232

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

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

Conversation

@dccakes

@dccakes dccakes commented Aug 3, 2026

Copy link
Copy Markdown
Owner

Daily Product Improvement

Summary

The dashboard page content wrapper was using a <div> instead of a <main> element, making it the only authenticated page missing the primary landmark. Screen readers rely on <main> to let users skip directly to page content. This was fixed by replacing <div> with <main> — same classes, no visual or functional change, full semantic correctness.


Recommendations Reviewed

1. Dashboard — Missing <main> landmark

  • Area: src/app/(authenicated)/dashboard/page.tsx
  • Issue: Content wrapper uses <div> instead of <main>, unlike every other authenticated page (events, vendors, checklist, guest list, budget all use <main> correctly)
  • Recommendation: Replace <div> with <main> to add the primary landmark
  • Type: UX/UI (accessibility)
  • Priority: High
  • Effort: Small

2. Checklist loading page — Missing topbar skeleton

  • Area: src/app/(authenicated)/checklist/loading.tsx
  • Issue: The loading skeleton has no topbar placeholder and no <main> wrapper, so the header region flashes empty during load. Dashboard, events, and vendors loading pages all include topbar skeletons.
  • Recommendation: Add topbar skeleton and <main> wrapper to match the established pattern
  • Type: UX/UI
  • Priority: Medium
  • Effort: Small

3. Settings page — Flat heading hierarchy

  • Area: src/app/(authenicated)/settings/page.tsx
  • Issue: <h2> ("Wedding Details") and all <h3> subsections ("Plugins", "Organization Members", "Connected Apps") share the same font-serif text-xl class, creating a visually flat page that's hard to scan
  • Recommendation: Reduce h3 to text-base or text-lg to establish clear visual hierarchy
  • Type: UX/UI
  • Priority: Medium
  • Effort: Small

4. EttaChat — Hardcoded color tokens

  • Area: src/components/etta/EttaChat.tsx lines 133–136
  • Issue: text-emerald-400, bg-emerald-400, and text-red-400 bypass the design token system for the AI status indicator
  • Recommendation: Replace with text-success, bg-success, and text-destructive respectively
  • Type: Frontend cleanup
  • Priority: Medium
  • Effort: Small

5. Guest list filter dropdowns — Custom DIV-based implementation

  • Area: src/components/guest-list/guest-search-filter.tsx
  • Issue: RSVP, Tag, and Country filter dropdowns use custom <div> popovers with useOuterClick rather than Radix Popover. No keyboard navigation (arrow keys, Escape), no role="listbox" or role="option" semantics.
  • Recommendation: Replace with Radix Popover + proper keyboard interaction
  • Type: Frontend cleanup + UX (accessibility)
  • Priority: High
  • Effort: Large

6. guests-view.tsx — Hardcoded amber colors

  • Area: src/components/guest-list/guests-view.tsx line 714
  • Issue: border-amber-500/40 bg-amber-500/10 text-amber-700 used for "Unsaved changes" badge — hardcoded and does not respect dark mode or design tokens (DESIGN.md prohibits hardcoded color values)
  • Recommendation: Replace with design token equivalents or text-warning if defined
  • Type: Frontend cleanup
  • Priority: Medium
  • Effort: Small

7. God components — Decomposition needed

  • Area: src/components/guest-list/guests-view.tsx (999 lines), src/components/vendor/vendor-detail-panel.tsx (936 lines)
  • Issue: Both manage 10+ pieces of state, multiple mutation hooks, dialogs, and business logic in a single component file, making them hard to maintain and test
  • Recommendation: Extract a custom hook per component (useGuestsView, useVendorDetail) plus split render into sub-components by concern
  • Type: Frontend cleanup
  • Priority: Medium
  • Effort: Large

Selected Improvement

Replace <div> with <main> in the dashboard page content wrapper — a single semantic HTML change restoring the primary landmark on the most-visited page.

Why This Was Selected

The dashboard is the entry point of the app and the page users see most. It was the only authenticated page missing a <main> landmark — every other page already uses it correctly. Without <main>, screen reader users cannot use the "jump to main content" shortcut, making the dashboard uniquely inaccessible versus the rest of the app. The fix is one tag swap with zero functional or visual impact, and it closes a clear gap in consistency.

Changes Made

  • Replaced <div className='min-h-0 flex-1 overflow-y-auto px-4 py-5 lg:px-6 lg:py-6'> with <main ...> (identical classes) in dashboard/page.tsx

Files Changed

  • src/app/(authenicated)/dashboard/page.tsx

Verification

  • Confirmed all other authenticated pages already use <main>: events, vendors, checklist, guest list, budget
  • Confirmed the dashboard loading skeleton (dashboard/loading.tsx) uses the same pattern correctly — no changes needed there
  • No functional change: classes, children, and layout behaviour are identical
  • No open PR previously addressed this

Future Recommendations

Checklist loading page — Missing topbar skeleton

  • Recommendation: Add topbar skeleton + <main> wrapper to checklist/loading.tsx to match events/vendors/dashboard loading pattern
  • Priority: Medium
  • Effort: Small
  • Reason not included: One improvement per day; this is the next logical follow-on
  • Should become GitHub issue: No

Settings page — Flat heading hierarchy

  • Recommendation: Reduce h3 elements in settings/page.tsx to text-base or text-lg for proper visual hierarchy
  • Priority: Medium
  • Effort: Small
  • Reason not included: Lower user impact than the accessibility gap fixed today
  • Should become GitHub issue: No

EttaChat — Hardcoded color tokens

  • Recommendation: Replace text-emerald-400, bg-emerald-400, text-red-400 with design token equivalents (text-success, bg-success, text-destructive)
  • Priority: Medium
  • Effort: Small
  • Reason not included: Scope limited to one improvement per run; no visual regression risk
  • Should become GitHub issue: No

Guest list filter dropdowns — Radix Popover migration

  • Recommendation: Replace custom DIV-based dropdowns in guest-search-filter.tsx with Radix Popover + accessible keyboard patterns
  • Priority: High
  • Effort: Large
  • Reason not included: Large effort; needs careful testing of all filter combinations and edge cases
  • Should become GitHub issue: Yes

God component decomposition

  • Recommendation: Split guests-view.tsx (999 lines) and vendor-detail-panel.tsx (936 lines) into custom hooks + focused sub-components
  • Priority: Medium
  • Effort: Large
  • Reason not included: Cross-cutting refactor requiring careful review; out of scope for a daily targeted run
  • Should become GitHub issue: Yes

GitHub Issues Created or Proposed

Two issues are recommended for tracking:

  1. [Guest List] Replace custom filter dropdowns with accessible Radix Popover components

    • Problem: RSVP, Tag, and Country filters use DIV-based dropdowns with no keyboard navigation or ARIA roles
    • Solution: Migrate to Radix Popover with role="listbox" / role="option" semantics and full keyboard support
    • Benefit: Accessibility compliance, consistency with the rest of the component library
    • Acceptance criteria: All three filter dropdowns operable by keyboard only; Escape closes popover; ARIA roles in place
    • Priority: High / Effort: Large
  2. [Guest List / Vendors] Decompose god components into hooks + focused sub-components

    • Problem: guests-view.tsx (999 lines) and vendor-detail-panel.tsx (936 lines) are each too large to maintain or test in isolation
    • Solution: Extract useGuestsView and useVendorDetail hooks; split render into sub-components by concern
    • Benefit: Maintainability, testability, reduced cognitive load for contributors
    • Acceptance criteria: Each component under 400 lines; hooks are independently unit-testable
    • Priority: Medium / Effort: Large

Generated by Claude Code

…ssibility

Every other authenticated page (events, vendors, checklist, guest list, budget)
uses a <main> element for its content wrapper. The dashboard was the only page
still using a <div>, preventing screen readers from navigating to main content
via the landmark shortcut on the most-visited page.

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

vercel Bot commented Aug 3, 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 3, 2026 10:18am

@github-actions

github-actions Bot commented Aug 3, 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 — 53001069 Deployed Aug 3, 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