Glassmorphic CTAReact + Tailwind + Framer Motion
Frosted Gel Dual-Pill Download Button
Dual-pill split CTA button featuring an elevated ceramic primary action, frosted glass cloud download tile, optical refraction rings, and volumetric blue underglow flare.
preview.tsx
Hover or click pill / cloud icon
Customizer
PRESETS & VARIATIONS
All Variants Preview
Hover & click each variant to experience frosted gel optical effects
Figma Electric Bluetheme="figma-blue"
Cyber Violettheme="cyber-violet"
Emerald Matrixtheme="emerald-matrix"
Magma Orangetheme="magma-orange"
Dark Obsidiantheme="dark-obsidian"
Titanium Goldtheme="titanium-gold"
Installation & Setup
Install the required dependencies for spring animations and styling:
npm install framer-motion clsx
Code & Integration
FrostedGelDownloadButton.tsx• Production Ready
"use client";
import React, { useState } from "react";
import { motion } from "framer-motion";
export type FrostedGelTheme =
| "figma-blue"
| "cyber-violet"
| "emerald-matrix"
| "magma-orange"
| "dark-obsidian"
| "titanium-gold";
export type FrostedGelStateMode = "interactive" | "standerd" | "hover";
export type FrostedGelSize = "xs" | "sm" | "md" | "lg" | "xl";
export interface FrostedGelButtonProps {
label?: string;
stateMode?: FrostedGelStateMode;
theme?: FrostedGelTheme;
size?: FrostedGelSize;
showCables?: boolean;
onDownloadClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
onIconClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;
disabled?: boolean;
className?: string;
}
export function FrostedGelDownloadButton({
label = "Download now",
stateMode = "interactive",
theme = "figma-blue",
size = "md",
showCables = true,
onDownloadClick,
onIconClick,
disabled = false,
className = "",
}: FrostedGelButtonProps) {
const [isHovered, setIsHovered] = useState(false);
const [isPressed, setIsPressed] = useState(false);
const scale = size === "sm" ? 0.8 : size === "lg" ? 1.2 : 1;
const isVisualHover = stateMode === "hover" || (stateMode === "interactive" && isHovered);
return (
<div
className={`relative select-none flex items-center justify-center ${className}`}
style={{ width: `${560 * scale}px`, height: `${240 * scale}px` }}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => {
setIsHovered(false);
setIsPressed(false);
}}
>
<div
className="relative w-[560px] h-[240px] flex items-center justify-center flex-none transition-transform duration-300"
style={{ transform: `scale(${scale})` }}
>
{/* Volumetric Underglow Flare */}
<div
className={`absolute w-[440px] h-[100px] rounded-full blur-[32px] transition-opacity duration-400 pointer-events-none ${
isVisualHover ? "opacity-100 scale-105" : "opacity-35"
}`}
style={{ background: "rgba(0, 123, 254, 0.35)" }}
/>
{/* Dual-Pill Assembly */}
<div className="relative flex items-center gap-3">
{/* Ceramic Pill */}
<motion.button
type="button"
disabled={disabled}
onClick={onDownloadClick}
onMouseDown={() => setIsPressed(true)}
onMouseUp={() => setIsPressed(false)}
animate={{
y: isPressed ? 2 : isVisualHover ? -4 : 0,
}}
transition={{ type: "spring", stiffness: 450, damping: 25 }}
className="relative px-8 py-4 rounded-[16.5px] bg-[#F9F9F9] border border-white/90 shadow-[0px_1px_0px_#002AFE,0px_8px_16px_rgba(0,42,254,0.18),inset_0px_3.3px_0px_1.2px_white] text-[#2626FF] font-bold text-sm flex items-center gap-2 cursor-pointer focus:outline-none"
>
<span>{label}</span>
</motion.button>
{/* Frosted Glass Gel Tile */}
<motion.button
type="button"
disabled={disabled}
onClick={onIconClick}
animate={{
y: isPressed ? 2 : isVisualHover ? -4 : 0,
}}
transition={{ type: "spring", stiffness: 450, damping: 25 }}
className="relative w-[60px] h-[54px] rounded-[16.5px] bg-white/40 backdrop-blur-md border border-white/70 shadow-[0px_8px_18px_rgba(0,42,254,0.25)] flex items-center justify-center text-[#2626FF] cursor-pointer focus:outline-none"
>
<svg className="w-5 h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<path strokeLinecap="round" strokeLinejoin="round" d="M3 15a4 4 0 004 4h9a5 5 0 10-.1-9.999 5.002 5.002 0 00-9.78 2.096A4.001 4.001 0 003 15z" />
</svg>
</motion.button>
</div>
</div>
</div>
);
}Component API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
| label | string | "Download now" | Text displayed on the primary ceramic pill |
| theme | FrostedGelTheme | "figma-blue" | Color scheme preset (Electric Blue, Ultraviolet, Emerald, etc.) |
| size | "xs" | "sm" | "md" | "lg" | "xl" | "md" | Physical scaling multiplier |
| icon | FrostedGelIcon | "cloud-download" | Icon rendered in the frosted gel tile (cloud-download, download, arrow-down, upload, folder, package, save) |
| onDownloadClick | (e) => void | undefined | Callback fired when the pill button is clicked |
| onIconClick | (e) => void | undefined | Callback fired when the frosted glass cloud tile is clicked |
Personalized Help
Struggling with frosted glass CTA buttons or component libraries? Let's talk about your product.
UI Pirate is a product design & development agency trusted by 50+ SaaS founders and enterprise teams across the US, UK & beyond. Tell us what you need.