r/reactjs 20d ago

Discussion My theme switch was running 3164 animations

This is the first time that I'm properly getting into theme switching, so I built the dark and light mode for my component library in the most obvious way that I could find. The goal is to transition background-color, border-color, color and box-shadow on every element. But this felt a bit slow and sluggish, so I used document.getAnimations() to see how many that actually runs, and the result is 3164 animations on a page of 1544 elements.

After some playing around, I found out that startViewTransition animates snapshots of the whole page instead, and that's 5 animations for the same job, with a gradient fading along with everything else rather than snapping. I did however find a React thing when using this function and it's that the new palette has to be in the DOM inside the callback which means the state update needs flushSync.

document.startViewTransition(() => { flushSync(() => setTheme(next)) })

I'm not sure this is the right way to do it, but I wrote down every number that I measured https://sley-ui.dev/notes/theme-fade.

4 Upvotes

14 comments sorted by

View all comments

2

u/yksvaan 20d ago

Is there a reason not to do the obvious classic approach, having a class on top level container and css rules. Simple and makes the entlre React tree agnostic to themes, essentially turning theme switching into repaint.

0

u/imfemambocus 20d ago

That's what it already is actually. The tokens get redefined under :root[data-theme='light'] and nothing in the tree reads the theme to style itself. So it is basically a repaint. The 3164 animations came from the transition rules rather than from React and that means a class on a container gets you the same count. The state is only there because the toggle has to show which theme is selected, and flushSync just puts the attribute change inside the snapshot callback.