Skip to content

Eliminate theme flash-of-unstyled-content with an inline pre-hydration script #27

Description

@mikewheeleer

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.

Metadata

Metadata

Assignees

No one assigned
    No fields configured for Feature.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions