Glassmorphic Pricing Card
A premium pricing card with glassmorphism, billing toggle, and spring animations.
Installation
Add this component to your project using the CLI:
terminal
npx vui-registry-cli-v1 add glassmorphic-pricing-cardSource Code
glassmorphic-pricing-card.tsx
'use client'
import React, { useState } from 'react'
import { motion, AnimatePresence } from 'framer-motion'
import { Check, X } from 'lucide-react'
import { cn } from '@/lib/utils'
export default function GlassmorphicPricingCard() {
const [billing, setBilling] = useState<'monthly' | 'yearly'>('monthly')
return (
<div className="flex items-center justify-center min-h-[600px] bg-neutral-100 dark:bg-neutral-950 p-8">
<div className="flex flex-col items-center gap-8">
{/* Toggle */}
<div className="bg-white dark:bg-neutral-900 p-1 rounded-full border border-neutral-200 dark:border-white/10 flex relative">
<motion.div
className="absolute top-1 bottom-1 w-[calc(50%-4px)] bg-black dark:bg-white rounded-full shadow-md z-0"
initial={false}
animate={{ x: billing === 'monthly' ? 0 : '100%' }}
transition={{ type: "spring", stiffness: 400, damping: 30 }}
/>
<button
onClick={() => setBilling('monthly')}
className={cn("px-6 py-2 rounded-full text-sm font-medium z-10 transition-colors relative", billing === 'monthly' ? "text-white dark:text-black" : "text-neutral-500 hover:text-neutral-900 dark:hover:text-white")}
>
Monthly
</button>
<button
onClick={() => setBilling('yearly')}
className={cn("px-6 py-2 rounded-full text-sm font-medium z-10 transition-colors relative", billing === 'yearly' ? "text-white dark:text-black" : "text-neutral-500 hover:text-neutral-900 dark:hover:text-white")}
>
Yearly <span className="text-[9px] ml-1 opacity-70 font-normal">(-20%)</span>
</button>
</div>
{/* Card */}
<PricingCard billing={billing} />
</div>
</div>
)
}
function PricingCard({ billing }: { billing: 'monthly' | 'yearly' }) {
const features = [
"Unlimited Projects",
"Advanced Analytics",
"Priority Support",
"Custom Domain",
"Team Collaboration",
"API Access"
]
return (
<motion.div
className="relative w-full max-w-sm rounded-[2.5rem] p-8 bg-white/60 dark:bg-neutral-900/60 backdrop-blur-xl border border-white/40 dark:border-white/5 shadow-2xl overflow-hidden group"
whileHover={{ y: -5 }}
transition={{ type: "spring", stiffness: 300, damping: 20 }}
>
{/* Shimmer Border */}
<div className="absolute inset-0 rounded-[2.5rem] p-[1px] bg-gradient-to-br from-transparent via-white/20 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-500 pointer-events-none" />
<div className="relative z-10">
<div className="flex justify-between items-start mb-6">
<div>
<h3 className="text-lg font-semibold text-neutral-900 dark:text-white mb-1">Pro Plan</h3>
<p className="text-sm text-neutral-500">Perfect for growing teams.</p>
</div>
<div className="px-3 py-1 rounded-full bg-black/5 dark:bg-white/10 border border-black/5 dark:border-white/5 text-[10px] font-bold uppercase tracking-wider text-neutral-900 dark:text-white">
Most Popular
</div>
</div>
<div className="flex items-baseline gap-1 mb-8">
<span className="text-4xl font-bold text-neutral-900 dark:text-white">
${billing === 'monthly' ? '49' : '39'}
</span>
<span className="text-sm text-neutral-500 font-medium">/mo</span>
</div>
<div className="space-y-4 mb-8">
{features.map((feature, i) => (
<div key={i} className="flex items-center gap-3">
<div className="w-5 h-5 rounded-full bg-green-500/10 flex items-center justify-center shrink-0">
<Check size={12} className="text-green-600 dark:text-green-400" strokeWidth={3} />
</div>
<span className="text-sm text-neutral-600 dark:text-neutral-300 font-medium">{feature}</span>
</div>
))}
</div>
<button className="w-full py-4 rounded-2xl bg-neutral-900 dark:bg-white text-white dark:text-black font-bold text-sm shadow-lg shadow-neutral-500/20 hover:scale-[1.02] active:scale-[0.98] transition-all">
Get Started Now
</button>
</div>
{/* Background Decorations */}
<div className="absolute -top-20 -right-20 w-64 h-64 bg-purple-500/10 rounded-full blur-3xl pointer-events-none" />
<div className="absolute -bottom-20 -left-20 w-64 h-64 bg-blue-500/10 rounded-full blur-3xl pointer-events-none" />
</motion.div>
)
}
Dependencies
framer-motion: latestlucide-react: latest

