Beautiful, smooth animations for theme switching in React applications. Built with TypeScript and powered by the View Transition API.
π Live Demo | π¦ npm Package | πΌ Hire me
- π΅ Circle: Smooth expanding circle transition
- π Blur Circle: Circle with elegant blur effect on the edges
- π± QR Scan: Scanning line sweeps left to right (like QR code reader)
- The hook is only available in the browser environment. So if you use NextJS App router or any other framework that uses Server Components, you should use this hook in a Client Component by adding the directive
use client
- Currently works only if the project is using TailwindCSS
- Ensure your project has the necessary TailwindCSS configuration for dark mode
- π¨ Multiple Animation Types: Circle, Blur Circle, and QR Scan animations
- β‘ High Performance: Optimized for high-resolution displays with smooth 60fps animations
- π― View Transition API: Leverages modern browser APIs for seamless transitions
- π± Responsive Design: Works perfectly across all device sizes and screen resolutions
- βΏ Accessibility First: Respects
prefers-reduced-motion
and provides fallback experiences - π§ TypeScript Support: Full TypeScript support for enhanced development experience
- πΎ State Persistence: Uses
localStorage
to persist theme state across sessions - ποΈ Highly Customizable: Configure duration, easing, blur amount, and more
- πͺ React Hooks: Clean, modern React Hooks API
Install the package using npm or YARN:
npm install react-theme-switch-animation
or
yarn add react-theme-switch-animation
Hereβs how to use the useModeAnimation
hook in your React component:
'use client'
import React from 'react'
import { useModeAnimation } from 'react-theme-switch-animation'
const MyComponent = () => {
const { ref, toggleSwitchTheme, isDarkMode } = useModeAnimation()
return (
<button ref={ref} onClick={toggleSwitchTheme}>
Toggle Dark Mode (Currently {isDarkMode ? 'Dark' : 'Light'} Mode)
</button>
)
}
export default MyComponent
useModeAnimation
accepts an optional props
object with the following properties:
Property | Type | Default | Description |
---|---|---|---|
duration |
number | 750 |
Duration of the animation in milliseconds. |
easing |
string | "ease-in-out" |
CSS easing type for the animation. |
pseudoElement |
string | "::view-transition-new(root)" |
Pseudo-element used for the animation. |
globalClassName |
string | "dark" |
Class name to apply to the root element. |
animationType |
ThemeAnimationType | ThemeAnimationType.CIRCLE |
Type of animation effect (CIRCLE , BLUR_CIRCLE , QR_SCAN ) |
blurAmount |
number | 2 |
Blur intensity for blur circle animation. |
styleId |
string | "theme-switch-style" |
ID for the style element (blur circle animation). |
isDarkMode |
boolean | false |
Initial dark mode state. |
onDarkModeChange |
(isDark: boolean) => void | undefined |
Callback function to handle dark mode change. |
The hook supports three types of animations:
ThemeAnimationType.CIRCLE
: A clean circle expansion animation (default)ThemeAnimationType.BLUR_CIRCLE
: A circle expansion with blur effect on the edgesThemeAnimationType.QR_SCAN
: A scanning line that sweeps from left to right
'use client'
import React from 'react'
import { ThemeAnimationType, useModeAnimation } from 'react-theme-switch-animation'
const CircleAnimation = () => {
const { ref, toggleSwitchTheme, isDarkMode } = useModeAnimation({
animationType: ThemeAnimationType.CIRCLE,
})
return (
<button ref={ref} onClick={toggleSwitchTheme}>
{isDarkMode ? 'π' : 'βοΈ'} Toggle Theme
</button>
)
}
'use client'
import React from 'react'
import { ThemeAnimationType, useModeAnimation } from 'react-theme-switch-animation'
const BlurCircleAnimation = () => {
const { ref, toggleSwitchTheme, isDarkMode } = useModeAnimation({
animationType: ThemeAnimationType.BLUR_CIRCLE,
blurAmount: 4, // Optional: adjust blur intensity
duration: 1000, // Optional: adjust animation duration
})
return (
<button ref={ref} onClick={toggleSwitchTheme}>
{isDarkMode ? 'π' : 'βοΈ'} Toggle Theme (Blur)
</button>
)
}
'use client'
import React from 'react'
import { ThemeAnimationType, useModeAnimation } from 'react-theme-switch-animation'
const QRScanAnimation = () => {
const { ref, toggleSwitchTheme, isDarkMode } = useModeAnimation({
animationType: ThemeAnimationType.QR_SCAN,
duration: 500, // Faster scan animation
})
return (
<button ref={ref} onClick={toggleSwitchTheme}>
{isDarkMode ? 'π' : 'βοΈ'} Toggle Theme (QR Scan)
</button>
)
}
Returns an object containing:
ref
: React ref for attaching to the component that will trigger the dark mode toggle.toggleSwitchTheme
: Function to toggle dark mode.isDarkMode
: Current state of dark mode (true
for dark,false
for light).
This library is built with performance in mind:
- High-Resolution Display Support: Automatically detects and optimizes for displays β₯3000px width/height
- Adaptive Animation Duration: Reduces duration by 20% on high-res displays for smoother experience
- GPU Acceleration: Uses hardware-accelerated CSS properties (
transform
,clip-path
,mask
) - Memory Efficient: Automatic cleanup of style elements and event listeners
- Accessibility: Respects
prefers-reduced-motion
for users who prefer minimal animations
- Modern Browsers: Chrome 111+, Firefox 103+, Safari 16.4+
- View Transition API: Falls back gracefully on unsupported browsers
- Progressive Enhancement: Basic theme switching works everywhere, animations enhance the experience
- React 16.8 or later (for Hooks support)
- TypeScript for compiling the package during installation
- TailwindCSS for styling (ensure dark mode is configured)
Contributions are welcome! Please open an issue or submit a pull request with your suggested changes.
MIT