gmorph-switch
v1.1.0
Published
Premium Glassmorphic switch components for React with View Transitions and smooth animations.
Maintainers
Readme
Glassmorphic Switch
A premium React UI component library providing high-quality, glassmorphic switches and buttons. Designed specifically for modern web applications to provide buttery-smooth, hardware-accelerated Theme and Language transitions.
🚀 Key Features
ThemeSwitch: A premium glassmorphic slider toggle that implements the browser's native View Transition API. Generates a custom radial sweep clip-path that originates directly from your mouse cursor click coordinates.LanguageSwitch: A custom toggle designed to animate translation states smoothly with fade cross-fade animations on language switch.GlassButton: A reusable glassmorphic utility button featuring custom hover states, active glows, and click scale animations.
📦 Installation
To integrate this library into your React, Next.js, or Vite project, run the following command:
npm install gmorph-switch[!NOTE] Make sure your project also has the required peer dependencies installed:
framer-motion(for slider animation support) andlucide-react(for sun/moon/icon rendering).
🎨 Styling Configuration (Required)
To enable the smooth PWA View Transition animations, copy the following CSS rules into your global stylesheet (e.g., globals.css or index.css):
/* ────────────────────────────────────────────────────────────────────────── */
/* ── VIEW TRANSITIONS (THEME CIRCULAR SWEEP EFFECTS) ── */
/* ────────────────────────────────────────────────────────────────────────── */
/* Disable standard browser cross-fade transitions */
::view-transition-old(root),
::view-transition-new(root) {
animation: none;
mix-blend-mode: normal;
}
/* Keyframes for expanding radial mask */
@keyframes theme-sweep-in {
from {
clip-path: circle(0px at var(--theme-x, 50%) var(--theme-y, 50%));
}
to {
clip-path: circle(var(--theme-r, 100vw) at var(--theme-x, 50%) var(--theme-y, 50%));
}
}
/* Keyframes for shrinking radial mask */
@keyframes theme-sweep-out {
from {
clip-path: circle(var(--theme-r, 100vw) at var(--theme-x, 50%) var(--theme-y, 50%));
}
to {
clip-path: circle(0px at var(--theme-x, 50%) var(--theme-y, 50%));
}
}
/* Light to Dark transition stacking: Dark (new view) sweeps on top of Light (old) */
.theme-to-dark::view-transition-new(root) {
animation: theme-sweep-in 500ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
z-index: 9999;
}
.theme-to-dark::view-transition-old(root) {
z-index: 1;
}
/* Dark to Light transition stacking: Dark (old view) shrinks on top of Light (new) */
.theme-to-light::view-transition-old(root) {
animation: theme-sweep-out 500ms cubic-bezier(0.4, 0, 0.2, 1) forwards;
z-index: 9999;
}
.theme-to-light::view-transition-new(root) {
z-index: 1;
}
/* ────────────────────────────────────────────────────────────────────────── */
/* ── VIEW TRANSITIONS (LANGUAGE FADE EFFECTS) ── */
/* ────────────────────────────────────────────────────────────────────────── */
@keyframes language-fade-out {
from { opacity: 1; }
to { opacity: 0; }
}
@keyframes language-fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
.lang-transitioning::view-transition-old(root) {
animation: language-fade-out 300ms ease-out forwards;
}
.lang-transitioning::view-transition-new(root) {
animation: language-fade-in 300ms ease-in forwards;
}🛠️ Usage Examples
[!IMPORTANT] React Asynchronous Batch Rendering Warning: React batches state changes and updates the DOM asynchronously. To make
document.startViewTransitionwork correctly, you MUST wrap the state update (e.g.setThemeorsetLanguage) insideflushSyncfromreact-dom. This forces React to flush updates to the DOM synchronously so the browser can capture the transition frames accurately without blinking.
1. Theme Toggler Example
Integration using next-themes (or similar theme provider):
import React from "react";
import { ThemeSwitch } from "gmorph-switch";
import { useTheme } from "next-themes";
import { flushSync } from "react-dom";
export default function Header() {
const { resolvedTheme, setTheme } = useTheme();
return (
<ThemeSwitch
theme={resolvedTheme as "light" | "dark"}
onChange={(nextTheme) => {
// flushSync forces React to write the theme class change to the DOM synchronously
flushSync(() => {
setTheme(nextTheme);
});
}}
/>
);
}2. Language Toggler Example
import React, { useState } from "react";
import { LanguageSwitch } from "gmorph-switch";
import { flushSync } from "react-dom";
export default function LanguagePanel() {
const [lang, setLang] = useState<"en" | "bn">("en");
return (
<LanguageSwitch
language={lang}
onChange={(nextLang) => {
// flushSync is required for seamless cross-fade transitions
flushSync(() => {
setLang(nextLang);
});
}}
/>
);
}3. Customizable Glassmorphic Button
import React from "react";
import { GlassButton } from "gmorph-switch";
export default function AppButton() {
return (
<GlassButton
active={true}
glowColor="rgba(244, 63, 94, 0.4)"
onClick={() => alert("Clicked!")}
>
Explore Workspace
</GlassButton>
);
}