npm.io
1.1.0 β€’ Published 3 weeks ago

react-theme-switch-animation

Licence
MIT
Version
1.1.0
Deps
2
Size
50 kB
Vulns
0
Weekly
0

React Theme Switch Animation Hook

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

Demo

Six Animation Types Available

  • 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)
  • Polygon: Diagonal wipe that sweeps across the screen
  • Polygon Gradient: Diagonal wipe with a soft gradient edge
  • Custom GIF: Reveal the new theme through any GIF mask of your choice

Notes

  • 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

Features

  • Multiple Animation Types: Circle, Blur Circle, QR Scan, Polygon, Polygon Gradient, and Custom GIF 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

Installation

Install the package using npm or YARN:

npm install react-theme-switch-animation

or

yarn add react-theme-switch-animation

Usage

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

API

useModeAnimation accepts an optional props object with the following properties:

Property Type Default Description
duration number 750 Duration of the animation in milliseconds (defaults to 1500 for POLYGON_GRADIENT and 2000 for GIF).
easing string "ease-in-out" CSS easing for the animation (defaults to an expo curve for POLYGON, POLYGON_GRADIENT, and GIF).
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, POLYGON, POLYGON_GRADIENT, GIF)
blurAmount number 2 Blur intensity for blur circle animation.
gifUrl string undefined URL of the GIF used as the reveal mask (required for the GIF animation type).
styleId string "theme-switch-style" ID for the injected style element (blur circle, polygon gradient, and gif animations).
isDarkMode boolean false Initial dark mode state.
onDarkModeChange (isDark: boolean) => void undefined Callback function to handle dark mode change.
Animation Types

The hook supports six types of animations:

  • ThemeAnimationType.CIRCLE: A clean circle expansion animation (default)
  • ThemeAnimationType.BLUR_CIRCLE: A circle expansion with blur effect on the edges
  • ThemeAnimationType.QR_SCAN: A scanning line that sweeps from left to right
  • ThemeAnimationType.POLYGON: A diagonal wipe β€” toward dark it sweeps from the top-left corner, back to light from the bottom-right
  • ThemeAnimationType.POLYGON_GRADIENT: A diagonal wipe with a soft gradient edge expanding from the top-left corner
  • ThemeAnimationType.GIF: Reveals the new theme through a custom GIF mask that scales up to fill the screen (requires gifUrl)
Examples for Each Animation Type
Circle Animation (Default)
'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>
  )
}
Blur Circle Animation
'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>
  )
}
QR Scan Animation
'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>
  )
}
Polygon Animation
'use client'

import React from 'react'
import { ThemeAnimationType, useModeAnimation } from 'react-theme-switch-animation'

const PolygonAnimation = () => {
  const { ref, toggleSwitchTheme, isDarkMode } = useModeAnimation({
    animationType: ThemeAnimationType.POLYGON,
  })

  return (
    <button ref={ref} onClick={toggleSwitchTheme}>
      {isDarkMode ? 'πŸŒ™' : 'β˜€οΈ'} Toggle Theme (Polygon)
    </button>
  )
}
Polygon Gradient Animation
'use client'

import React from 'react'
import { ThemeAnimationType, useModeAnimation } from 'react-theme-switch-animation'

const PolygonGradientAnimation = () => {
  const { ref, toggleSwitchTheme, isDarkMode } = useModeAnimation({
    animationType: ThemeAnimationType.POLYGON_GRADIENT,
    duration: 1500, // Optional: defaults to 1500ms for this animation
  })

  return (
    <button ref={ref} onClick={toggleSwitchTheme}>
      {isDarkMode ? 'πŸŒ™' : 'β˜€οΈ'} Toggle Theme (Polygon Gradient)
    </button>
  )
}
Custom GIF Animation
'use client'

import React from 'react'
import { ThemeAnimationType, useModeAnimation } from 'react-theme-switch-animation'

const GifAnimation = () => {
  const { ref, toggleSwitchTheme, isDarkMode } = useModeAnimation({
    animationType: ThemeAnimationType.GIF,
    gifUrl: 'https://media.tenor.com/cyORI7kwShQAAAAi/shigure-ui-dance.gif', // Any GIF URL
    duration: 2000, // Optional: defaults to 2000ms for this animation
  })

  return (
    <button ref={ref} onClick={toggleSwitchTheme}>
      {isDarkMode ? 'πŸŒ™' : 'β˜€οΈ'} Toggle Theme (GIF)
    </button>
  )
}

Tip: GIFs with transparent backgrounds work best as masks β€” the theme is revealed through the opaque parts of the GIF. If gifUrl is omitted, the hook falls back to the circle animation.

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).

Performance & Optimization

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

Browser Support

  • 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

Requirements

  • React 16.8 or later (for Hooks support)
  • TypeScript for compiling the package during installation
  • TailwindCSS for styling (ensure dark mode is configured)

Acknowledgements

The polygon, polygon gradient, and GIF animations are inspired by rudrodip/theme-toggle-effect.

Contributing

Contributions are welcome! Please open an issue or submit a pull request with your suggested changes.

License

MIT

Keywords