Skip to content

fix(leaderboard): resolve accessibility issues (W3C, Lighthouse 100%, Keyboard nav, VoiceOver)#165

Merged
ViktorSvertoka merged 3 commits into
developfrom
feature/accessibility-audit
Jan 19, 2026
Merged

fix(leaderboard): resolve accessibility issues (W3C, Lighthouse 100%, Keyboard nav, VoiceOver)#165
ViktorSvertoka merged 3 commits into
developfrom
feature/accessibility-audit

Conversation

@AlinaRyabova
Copy link
Copy Markdown
Collaborator

@AlinaRyabova AlinaRyabova commented Jan 19, 2026

Summary

This PR fixes critical accessibility and semantic HTML issues on the Leaderboard page and Global Header. The goal was to achieve WCAG compliance and pass automated audits.

🛠 Key Changes

1. HTML Semantics & W3C Validation

  • Fixed nested <main> tags (replaced inner main with div wrapper).
  • Corrected heading hierarchy (h1 -> h2 -> h3).
  • Removed invalid aria-label attributes on div elements.
  • Result: W3C Validator passed with 0 Errors.

2. Accessibility (A11y)

  • Tabs Component: Fixed aria-controls and ID references (removed spaces in IDs) to ensure proper screen reader navigation.
  • Mobile Menu: Fixed global aria-controls error where the button referenced a non-existent ID when the menu was closed.
  • Cookie Banner: Fixed heading hierarchy inside the banner.

3. Metadata

  • Added export const metadata to leaderboard/page.tsx (fixed missing <title> error).

✅ Verification Results

  • Google Lighthouse Accessibility: 🟢 100%
  • W3C Validator:Passed (No Errors)
  • Keyboard Navigation: Verified (Tab order works for Tabs, Buttons, and Cookie Banner).
  • Screen Reader: Verified navigation logic.

Summary by CodeRabbit

  • New Features

    • Added SEO metadata for the leaderboard page
    • Added leaderboard translations (en/pl/uk) and intl hooks
  • Style

    • Redesigned leaderboard UI: updated podium, avatars, table visuals, gradients and animations
    • Simplified layout by removing tabbed filters and updating empty-state messaging
  • Accessibility

    • Made mobile menu aria-controls conditional and changed cookie banner heading semantics

✏️ Tip: You can customize this high-level summary in your review settings.

@netlify
Copy link
Copy Markdown

netlify Bot commented Jan 19, 2026

Deploy Preview for develop-devlovers ready!

Name Link
🔨 Latest commit 3d86d62
🔍 Latest deploy log https://app.netlify.com/projects/develop-devlovers/deploys/696e6b0edd1a3d0008c1cdec
😎 Deploy Preview https://deploy-preview-165--develop-devlovers.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 19, 2026

📝 Walkthrough

Walkthrough

Adds Next.js Metadata export to the leaderboard page, introduces i18n leaderboard keys, removes the LeaderboardTabs component, updates leaderboard client/podium/table UI and styling, tweaks mobile menu aria-controls, and changes CookieBanner title from an h3 to a div.

Changes

Cohort / File(s) Summary
Leaderboard Page Metadata
frontend/app/[locale]/leaderboard/page.tsx
Adds exported metadata: Metadata with title and description for the leaderboard route.
Leaderboard client & podium
frontend/components/leaderboard/LeaderboardClient.tsx, frontend/components/leaderboard/LeaderboardPodium.tsx
Refactors layout and visuals: replaces decorative elements with animated blobs, updates header to use i18n (emoji/title/subtitle), reworks podium markup, avatar rendering (Next.js Image fill), styling, and animations.
Leaderboard table & translations
frontend/components/leaderboard/LeaderboardTable.tsx, frontend/messages/en.json, frontend/messages/pl.json, frontend/messages/uk.json
Adds leaderboard translation keys and integrates useTranslations; replaces static table headers/captions with translated strings, updates table styling, avatar bubble, hover interactions, and conditional rising indicator.
Removed tabs component
frontend/components/leaderboard/LeaderboardTabs.tsx
Deletes the LeaderboardTabs component and its tab UI (tab switching removed).
Header accessibility
frontend/components/header/AppMobileMenu.tsx
Conditional aria-controls on mobile menu button: set only when menu is open.
Cookie banner semantics
frontend/components/shared/CookieBanner.tsx
Changes title element from h3 to div (semantic heading → non-heading).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • AM1007
  • ViktorSvertoka

Poem

🐇✨ I hopped in with a tiny cheer,
New metadata whispered near,
Podiums bloom with translated light,
Tabs fell silent, avatars bright,
A rabbit danced — the leaderboard’s here! 🏆

🚥 Pre-merge checks | ✅ 2 | ❌ 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 (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(leaderboard): resolve accessibility issues (W3C, Lighthouse 100%, Keyboard nav, VoiceOver)' is directly related to the main objectives of the PR, which focus on fixing accessibility and semantic HTML issues, achieving WCAG compliance, and passing automated audits.

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

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown
Contributor

@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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/components/leaderboard/LeaderboardTable.tsx (1)

13-15: Hardcoded caption should be translated for i18n consistency.

The table caption provides important accessibility context for screen readers but remains hardcoded in English while the rest of the component uses translated strings. Consider adding a translation key for this caption.

Suggested fix

Add a new key to your translation files:

"tableCaption": "Leaderboard ranking for other participants"

Then update the caption:

-        <caption className="sr-only">
-          Leaderboard ranking for other participants
-        </caption>
+        <caption className="sr-only">
+          {t('tableCaption')}
+        </caption>
🤖 Fix all issues with AI agents
In `@frontend/components/leaderboard/LeaderboardClient.tsx`:
- Around line 44-46: Replace the hardcoded "Champions Arena" label in the
LeaderboardClient component with a translation key: add "championsArena":
"Champions Arena" to your locale JSON files and update the span in
LeaderboardClient.tsx to use the existing translation function (e.g.,
t('championsArena') / i18n.t('championsArena')) instead of the literal string;
keep the span's className and accessibility unchanged and provide a sensible
fallback if your translation helper supports one.

In `@frontend/components/leaderboard/LeaderboardPodium.tsx`:
- Around line 77-81: Replace the hardcoded "pts" suffix in the LeaderboardPodium
component with a translatable string: import and use the existing
useTranslations hook (or i18n utility used in the project) inside
LeaderboardPodium to get t('pts') and render that instead of the literal "pts";
also add the "pts" key to the locale JSON files (e.g., "pts": "pts" for en and
appropriate translations for other locales). Ensure you reference the t function
where {user.points} is rendered so the suffix becomes {t('pts')} (or the
project's equivalent lookup).
- Around line 10-12: The hardcoded aria-label on the ol in LeaderboardPodium.tsx
should be localized: import and call the project i18n hook (e.g.,
useTranslations) inside the LeaderboardPodium component to read a new key (e.g.,
"topThreeLabel") from translations and replace the static aria-label="Top 3
Leaders" with aria-label={t('topThreeLabel')}; also add "topThreeLabel": "Top 3
Leaders" to your locale translation files so the key resolves.
🧹 Nitpick comments (2)
frontend/components/leaderboard/LeaderboardTable.tsx (2)

63-66: Consider conditionally displaying the "Rising" indicator based on actual change data.

The User type includes a change field, but the "Rising" indicator displays unconditionally for all users on hover. This could be misleading if a user's ranking is actually falling.

Suggested conditional rendering
-                    <span className="flex items-center gap-1 text-[10px] text-emerald-600 dark:text-emerald-400 font-bold uppercase tracking-wide opacity-0 group-hover:opacity-100 transition-opacity">
-                      <TrendingUp className="w-3 h-3" aria-hidden="true" />
-                      {t('rising')}
-                    </span>
+                    {user.change > 0 && (
+                      <span className="flex items-center gap-1 text-[10px] text-emerald-600 dark:text-emerald-400 font-bold uppercase tracking-wide opacity-0 group-hover:opacity-100 transition-opacity">
+                        <TrendingUp className="w-3 h-3" aria-hidden="true" />
+                        {t('rising')}
+                      </span>
+                    )}

71-75: Consider using locale-aware number formatting for points.

Raw numeric output loses locale-specific formatting (e.g., 1,000 vs 1.000 vs 1 000). For consistency with the i18n approach, consider using toLocaleString() or a formatting utility.

Suggested fix
-                <span className="font-mono font-bold text-slate-800 dark:text-slate-100 group-hover:scale-105 inline-block transition-transform">
-                  {user.points}
-                </span>
+                <span className="font-mono font-bold text-slate-800 dark:text-slate-100 group-hover:scale-105 inline-block transition-transform">
+                  {user.points.toLocaleString()}
+                </span>

Comment thread frontend/components/leaderboard/LeaderboardClient.tsx
Comment thread frontend/components/leaderboard/LeaderboardPodium.tsx Outdated
Comment thread frontend/components/leaderboard/LeaderboardPodium.tsx
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.

2 participants