Animation & Transition
@theme-kit/core — transition pipeline
Theme Kit owns the entire visual update for a theme change — diff what actually changed, plan which properties may animate, and run one coordinated, lag-free transition. Enable it with a one-line transition prop and pick a preset; nothing else is required.
1Enable it
1import { ThemeProvider } from "@theme-kit/react";
2
3<ThemeProvider
4 themes={themes}
5 defaultTheme="theme-kit-default-light"
6 transition={{ enabled: true, preset: "smooth" }}
7>
8 <YourApp />
9</ThemeProvider>Same prop on every framework
transition={{ enabled: true, preset: "smooth" }}:transition="{ enabled: true, preset: 'smooth' }"provideThemeKit({ transition: { enabled: true, preset: "smooth" } })<theme-kit-provider transition='{"enabled":true,"preset":"smooth"}'></theme-kit-provider>createThemeRuntime({ transition: { enabled: true, preset: "smooth" } })@import "@theme-kit/tailwind"2Enable transitions in your framework
Pass the same transition object to your provider (or runtime). Every framework exposes it with the same shape — only the binding syntax changes.
1import { ThemeProvider, ThemeScope } from "@theme-kit/react";
2import { themes } from "./themes";
3
4export function App() {
5 return (
6 <ThemeProvider
7 themes={themes}
8 defaultTheme="theme-kit-default-light"
9 transition={{ enabled: true, preset: "smooth" }}
10 >
11 <YourApp />
12
13 {/* Nested region with its own theme + transition */}
14 <ThemeScope
15 theme="plum-dark"
16 transition={{ enabled: true, duration: 300, easing: "ease" }}
17 >
18 <Widget />
19 </ThemeScope>
20 </ThemeProvider>
21 );
22}- Install the framework package (
@theme-kit/react,@theme-kit/vue, etc.). - Register your themes with the provider or runtime.
- Enable transitions by adding the
transitionprop (:transitionin Vue/Svelte/Nuxt, attribute JSON in Web Components). - Choose a preset —
"smooth"works for most sites. - Scope a nested region with
ThemeScope(themeKitScopein Angular,theme-kit-scopein Web Components) for independent subtrees.
3View Transitions API
1import { createThemeRuntime } from "@theme-kit/core";
2
3const runtime = createThemeRuntime({
4 themes,
5 transition: {
6 enabled: true,
7 useViewTransition: true,
8 duration: 300,
9 },
10});useViewTransition: true the new theme is painted beneath a fading snapshot of the old one — the opposite of interpolating directly from near-white colors — so light→dark switches never wash through white. Browsers without the API (Firefox/Safari) fall back to the inherited --theme-color-* interpolation automatically.4Things to avoid
Theme transitions are owned by theme-kit. The provider's transition engine (configured via the transition prop on ThemeProvider or createThemeRuntime) interpolates the inherited --theme-color-* variables every time the active theme changes — automatically, with no extra CSS from you. This is how every theme switch on this docs site animates smoothly, and it works the same way in your app. You don't need to (and should not) add your own color transition.
If you do add one — a transition-colors utility class in Tailwind, or a plain transition: background-color 0.3s in native CSS — that element re-eases the same value again, on top of theme-kit's own interpolation. The result is a double-eased, laggy switch. Leave color transitions to the library, in both Tailwind and hand-written CSS.
1/* ── Tailwind ─────────────────────────────────────────────────────── */
2/* ✗ DON'T — animating theme tokens via Tailwind utility classes */
3.btn {
4 @apply transition-colors; /* ← re-eases theme colors → lag */
5}
6.card {
7 @apply transition-all; /* ← catches managed properties too */
8}
9
10/* ✓ DO — animate non-theme properties with Tailwind */
11.btn {
12 @apply transition-transform duration-200;
13}
14.btn:hover {
15 @apply -translate-y-0.5; /* hover lift — fine */
16}
17
18/* ── Native CSS ───────────────────────────────────────────────────── */
19/* ✗ DON'T — color transition on themed elements */
20button {
21 transition: background-color 0.3s; /* ← re-eases inherited var → lag */
22}
23* {
24 transition: color 0.2s, background-color 0.2s; /* ← catches everything */
25}
26
27/* ✓ DO — animate properties the theme doesn't manage */
28.toast {
29 transition: opacity 0.2s ease, transform 0.2s ease;
30}
31.card {
32 transition: box-shadow 0.2s ease, transform 0.2s ease;
33}- Tailwind: use
transition-transform/transition-opacitywithhover:scale,hover:translate,hover:shadow. - Native CSS: write
transition: transform 0.2s ease,opacity 0.2s,box-shadow 0.2son toasts, overlays, and cards — none of these are theme-managed. - Both: animate
outline/outline-offsetfor focus rings.
- Tailwind: don't add
transition-colorsto buttons, cards, or links whose colors are theme tokens — the provider already animates those colors on theme change. Avoidtransition-alltoo, which catches the managed properties. - Native CSS: don't write a
transitionforcolor,background-color,border-coloron:root,*, or any themed element — theme-kit handles that interpolation for you.
5API Reference
| Export | Module | Description |
|---|---|---|
ThemeTransitionOptions | transition | Interface for configuring transitions — enabled, duration, easing, useViewTransition, preset, properties. |
TransitionPreset | transition | "smooth" | "subtle" | "instant" | "custom" | string[] — how the transition is filtered. |
TRANSITION_PRESETS | transition | The curated property lists behind the smooth / subtle / instant presets. |
DEFAULT_TRANSITION_PRESET | transition | The default preset — "smooth". |
DEFAULT_THEME_TRANSITION | transition | Built-in defaults: enabled, 300ms, cubic-bezier(0.4, 0, 0.2, 1), smooth property list. |
createThemeDiff | animation | Compare two variable maps and report which token groups changed. |
createTransitionPlan | animation | Turn a ThemeDiff into a TransitionPlan; null when nothing can or should animate. |
scanForTransition | animation | TreeWalker scan for elements whose computed style uses a planned property. |
runThemeAnimation | animation | Run the attach → flush → swap → cleanup sequence for a theme change. |
cancelThemeAnimation | animation | Abort an in-flight theme animation and remove its temporary styles. |
ThemeDiff / TransitionPlan | animation | Types describing what changed and how to animate it. |
createAnimationsPlugin | @theme-kit/core | Official plugin — attaches a CSS transition to <html> (options.transition) via onBeforeThemeChange. A lightweight, manual alternative to the built-in runtime pipeline. |
runtime.store.set(theme, { suppressTransition: true }) | @theme-kit/core | The runtime-level toggle. Transitions are configured once at runtime creation; this per-update option forces an instant, non-animated apply for a single switch. |