Skip to content

Commit b3f2fb8

Browse files
fix(theme): disable animations during theme switch for instant transition (#853)
1 parent 5d690c7 commit b3f2fb8

2 files changed

Lines changed: 20 additions & 0 deletions

File tree

src/components/ThemeProvider.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ const getSystemTheme = createIsomorphicFn()
4242

4343
const updateThemeClass = createClientOnlyFn((themeMode: ThemeMode) => {
4444
const root = document.documentElement
45+
root.classList.add('theme-switching')
46+
4547
root.classList.remove('light', 'dark', 'auto')
4648
const newTheme = themeMode === 'auto' ? getSystemTheme() : themeMode
4749
root.classList.add(newTheme)
@@ -57,6 +59,15 @@ const updateThemeClass = createClientOnlyFn((themeMode: ThemeMode) => {
5759
newTheme === 'dark' ? THEME_COLORS.dark : THEME_COLORS.light,
5860
)
5961
}
62+
63+
// Force reflow so the no-transition styles apply to the theme change,
64+
// then remove the class on the next frame so subsequent interactions animate.
65+
void root.offsetHeight
66+
requestAnimationFrame(() => {
67+
requestAnimationFrame(() => {
68+
root.classList.remove('theme-switching')
69+
})
70+
})
6071
})
6172

6273
const getNextTheme = createClientOnlyFn((current: ThemeMode): ThemeMode => {

src/styles/app.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@
77
@custom-variant auto (&:is(.auto, .auto *));
88
@custom-variant aria-current (&[aria-current="location"]);
99

10+
html.theme-switching,
11+
html.theme-switching *,
12+
html.theme-switching *::before,
13+
html.theme-switching *::after {
14+
transition: none !important;
15+
animation-duration: 0s !important;
16+
animation-delay: 0s !important;
17+
}
18+
1019
@theme {
1120
/* Breakpoints */
1221
--breakpoint-xs: 480px;

0 commit comments

Comments
 (0)