Liquid Glass

PreviousNext

A smooth glass effect with subtle blur, ideal for UI highlights and overlays.

Docs
paceuiui

Preview

Loading preview…
gsap/liquid-glass.tsx
"use client";

import { CSSProperties, useRef } from "react";

import { useGSAP } from "@gsap/react";
import gsap from "gsap";

import { cn } from "@/lib/utils";

type LiquidGlassProps = {
    width?: number;
    height?: number;
    borderRadius?: number;
    tintOpacity?: number;
    blur?: number;
};

export const LiquidGlass = (props: LiquidGlassProps) => {
    const { width = 120, height = 120, borderRadius = 12, tintOpacity = 0.1, blur = 2 } = props;

    const glassRef = useRef<HTMLDivElement>(null);

    useGSAP(() => {
        const glass = glassRef.current;
        const parent = glass?.parentElement;

        if (!glass || !parent) return;

        const mouseMove = (e: MouseEvent) => {
            if (!glassRef.current || !glassRef.current?.parentElement) return;

            const parentRect = parent.getBoundingClientRect();

            const posX = e.clientX - parentRect.left - width / 2;
            const posY = e.clientY - parentRect.top - height / 2;

            gsap.to(glassRef.current, {
                duration: 0.6,
                left: posX,
                top: posY,
                ease: "power2.out",
            });
        };

        if (!glassRef.current) return;

        if (parent) {
            window.addEventListener("mousemove", mouseMove);
        }

        return () => {
            window?.removeEventListener("mousemove", mouseMove);
        };
    }, []);

    return (
        <>
            <svg xmlns="http://www.w3.org/2000/svg" width="0" height="0" className="absolute overflow-hidden">
                <defs>
                    <filter id="glass-distortion" x="0%" y="0%" width="100%" height="100%">
                        <feTurbulence
                            type="fractalNoise"
                            baseFrequency="0.008 0.008"
                            numOctaves="2"
                            seed="92"
                            result="noise"></feTurbulence>
                        <feGaussianBlur in="noise" stdDeviation="2" result="blurred"></feGaussianBlur>
                        <feDisplacementMap
                            in="SourceGraphic"
                            in2="blurred"
                            scale="80"
                            xChannelSelector="R"
                            yChannelSelector="G"></feDisplacementMap>
                    </filter>
                </defs>
            </svg>
            <div
                ref={glassRef}
                className={cn(
                    "absolute isolate z-999 rounded-(--lg-border-radius) shadow-lg",
                    [
                        "before:absolute before:inset-0 before:z-0 before:rounded-(--lg-border-radius) before:bg-[rgba(255,255,255,var(--lg-tint-opacity))] before:shadow-[inset_0_0_20px_-5px_rgba(255,255,255,0.7)] before:content-['']",
                    ],
                    [
                        "after:absolute after:inset-0 after:isolate after:-z-1 after:rounded-(--lg-border-radius) after:[filter:url(#glass-distortion)] after:backdrop-blur-[var(--lg-blur)] after:content-['']",
                    ],
                )}
                style={
                    {
                        "--lg-border-radius": `${borderRadius}px`,
                        "--lg-tint-opacity": tintOpacity,
                        "--lg-blur": `${blur}px`,
                        width: width,
                        height: height,
                    } as CSSProperties
                }></div>
        </>
    );
};

Installation

npx shadcn@latest add @paceui/liquid-glass

Usage

import { LiquidGlass } from "@/components/ui/liquid-glass"
<LiquidGlass />