Improve theme initialization to remove the dark-mode flash
Description
src/components/ThemeToggle.tsx only applies the dark class inside a useEffect, after hydration, so users who chose dark (or whose system is dark) see a flash of light theme on every load. The root src/app/layout.tsx renders <html lang="en"> with no pre-paint theme application. This issue removes the FOUC.
Requirements and context
- Repository scope: StableRoute-Org/Stableroute-frontend only.
- Add an inline, blocking script in
layout.tsx (before paint) that reads stableroute.theme from localStorage and applies the dark class on <html> using the same logic as src/lib/theme.ts's effectiveTheme.
- Keep the script tiny and dependency-free; ensure it cannot throw if localStorage is unavailable.
- Keep
ThemeToggle as the source of truth for user changes and ensure no double-toggle/mismatch after hydration.
- Respect
prefers-color-scheme for the system setting.
Suggested execution
- Fork the repo and create a branch
git checkout -b a11y/theme-27-no-fouc
- Implement changes
- Test and commit
Test and commit
- Run
npm run lint, npm test, and npm run build, then manually verify no light flash in dark mode via npm run dev.
- Cover edge cases: stored dark, stored light, system dark, system light, and storage-throws.
- Include the full
npm test output in the PR description.
Example commit message
feat: apply theme pre-hydration to remove dark-mode flash
Guidelines
- Minimum 95 percent test coverage for impacted modules.
- Clear, reviewer-focused documentation.
- Timeframe: 96 hours.
Community & contribution rewards
- 💬 Join the StableRoute community on Discord for questions, reviews, and faster merges: https://discord.gg/37aCpusvx
- ⭐ This is a GrantFox OSS / Official Campaign task and may be rewarded. When your PR is merged you'll be prompted to rate the project — if this issue and the maintainers helped you ship, we'd be grateful for a 5-star rating. Clear questions in Discord and tidy, well-tested PRs are the fastest path to a merge and a reward.
Improve theme initialization to remove the dark-mode flash
Description
src/components/ThemeToggle.tsxonly applies thedarkclass inside auseEffect, after hydration, so users who chose dark (or whose system is dark) see a flash of light theme on every load. The rootsrc/app/layout.tsxrenders<html lang="en">with no pre-paint theme application. This issue removes the FOUC.Requirements and context
layout.tsx(before paint) that readsstableroute.themefrom localStorage and applies thedarkclass on<html>using the same logic assrc/lib/theme.ts'seffectiveTheme.ThemeToggleas the source of truth for user changes and ensure no double-toggle/mismatch after hydration.prefers-color-schemefor thesystemsetting.Suggested execution
git checkout -b a11y/theme-27-no-foucsrc/app/layout.tsx; keepsrc/lib/theme.tsas the shared logic reference.src/lib/__tests__/themeScript.test.tscovering the resolution branches of the inlined logic.README.md.Test and commit
npm run lint,npm test, andnpm run build, then manually verify no light flash in dark mode vianpm run dev.npm testoutput in the PR description.Example commit message
feat: apply theme pre-hydration to remove dark-mode flashGuidelines
Community & contribution rewards