Velocity UI
Loading…
Menu

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-card

Source 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: latest
  • lucide-react: latest