Skip to content

Move Theme State to URL - #102

Merged
romanaduraciova merged 3 commits into
devfrom
move-theme-state-to-url
Jul 27, 2026
Merged

Move Theme State to URL#102
romanaduraciova merged 3 commits into
devfrom
move-theme-state-to-url

Conversation

@xcillik

@xcillik xcillik commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

What was done

1. Theme state moved to URL params (?theme=eosc&mode=dark)
The theme switcher state is now shareable via URL. Precedence: URL param > localStorage > hardcoded default. When you switch themes, the URL updates via router.replace (no full navigation) and localStorage is kept in sync as a cache. Browser back/forward re-syncs the theme from the URL.
Files: src/hooks/use-theme-switcher.ts (URL read/write logic), src/components/ThemeSelector.tsx (Suspense boundary for useSearchParams), src/app/layout.tsx (inline FOUC script extended to read URL params).
2. next-themes removed entirely
After auditing all theme-related files, next-themes was found to be strictly redundant: it only managed the .dark class (which the custom system already handled), used a separate localStorage key ("theme" vs "theme-color-mode"), had no concept of branding (data-theme), and no URL param support. The only sync point was a fragile manual dual-call in ThemeSelector (setDefaultTheme(mode) + setTheme(mode)), and any theme change bypassing that call would silently desync the two systems.
Files deleted: src/components/ThemeProvider.tsx, src/components/ThemeInitializer.tsx (the latter was also redundant with the inline FOUC script and contained an unfixed dataset.Theme capitalization bug). next-themes removed from package.json peerDeps and vite.config.lib.ts externals.
3. Sonner made theme-agnostic
The library's Toaster component was the only library file importing next-themes (to read useTheme().theme for toast styling). It now accepts an optional theme prop instead, so the library no longer forces consumers to install next-themes.
File: lib/components/primitives/sonner.tsx.

Why it was needed

The original codebase had four competing mechanisms managing the .dark class using two different localStorage keys, with a single manual call in ThemeSelector keeping them aligned. Adding URL param support on top of that would have made the desync problem worse — URL-triggered theme changes (shared links, browser navigation) bypass ThemeSelector entirely, so next-themes would go stale while the custom system stayed correct. Removing next-themes eliminated the entire class of sync bugs and simplified the architecture to one system, one localStorage key set, and one FOUC script.

Closes #76

@xcillik xcillik changed the title Move theme state to url Move Theme State to URL Jul 24, 2026
@romanaduraciova
romanaduraciova merged commit 477c838 into dev Jul 27, 2026
1 check passed
@romanaduraciova
romanaduraciova deleted the move-theme-state-to-url branch July 27, 2026 11:51
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