A theme switch that wipes the new theme across the page with the View Transitions API.
Installation
Usage
<script setup lang="ts">
import { useColorMode } from '@vueuse/core';
import {
ThemeToggler,
type ThemeSelection,
} from '@animate-ui/vue/primitives/effects/theme-toggler';
const { store, system } = useColorMode();
</script>
<template>
<ThemeToggler
:theme="store as ThemeSelection"
:resolved-theme="system === 'dark' || store === 'dark' ? 'dark' : 'light'"
:set-theme="(theme) => (store = theme === 'system' ? 'auto' : theme)"
>
<template #default="{ effective, toggleTheme }">
<button @click="toggleTheme(effective === 'dark' ? 'light' : 'dark')">
{{ effective === 'dark' ? 'Light mode' : 'Dark mode' }}
</button>
</template>
</ThemeToggler>
</template>During the wipe, the dark class is toggled on <html>: this matches class-based dark mode (Tailwind's default, VueUse's useColorMode).
Animation
- The new theme is revealed with a clip-path wipe over 700ms with an
ease-in-out, indirection(left to right by default). The old and new pages are snapshots, so nothing re-renders mid-wipe. - The whole page is wiped at once: elements named for other view transitions (a header kept across pages) are wiped with it, not crossfaded on their own.
set-themeis called once the wipe finishes;@immediate-changefires right away.- Switching to
systemwhen it resolves to the current theme changes nothing on screen, so there is no wipe. - Browsers without the View Transitions API swap the theme at once.
<AnimateUIProvider :tempo>paces the wipe.- Under reduced motion, the theme swaps at once, without the wipe.
- On the server and while hydrating, the render function receives
effective: 'system'andresolved: 'light', since the theme is only known on the client.
API Reference
ThemeToggler
| Prop | Type | Default |
|---|---|---|
theme | 'light' | 'dark' | 'system' | - |
resolved-theme | 'light' | 'dark' | - |
set-theme | (theme: 'light' | 'dark' | 'system') => void | - |
direction? | 'btt' | 'ttb' | 'ltr' | 'rtl' | 'ltr' |
on-immediate-change? | (theme: 'light' | 'dark' | 'system') => void | - |
#default? | slot, with { resolved: 'light' | 'dark'; effective: 'light' | 'dark' | 'system'; toggleTheme: (theme: 'light' | 'dark' | 'system') => void } | - |
Credits
- Inspired by Magic UI's animated theme toggler.