Glass Card
Original · freeA frosted glassmorphism card over a soft gradient.
Copy prompt gives Claude Code, Cursor or v0 a ready-to-paste prompt that recreates this exact component.
npx shadcn@latest add https://webinnoventix.com/r/card-glass.json"use client";
import { useId, useRef, useState } from "react";
import { AnimatePresence, motion, useReducedMotion } from "motion/react";
type CopyButtonProps = {
value: string;
label: string;
};
function CopyButton({ value, label }: CopyButtonProps) {
const [copied, setCopied] = useState(false);
const timer = useRef<ReturnType<typeof setTimeout> | null>(null);
async function handleCopy() {
try {
await navigator.clipboard.writeText(value);
setCopied(true);
if (timer.current) clearTimeout(timer.current);
timer.current = setTimeout(() => setCopied(false), 1600);
} catch {
setCopied(false);
}
}
return (
<button
type="button"
onClick={handleCopy}
aria-label={copied ? "Copied to clipboard" : label}
className="group inline-flex h-9 w-9 items-center justify-center rounded-full border border-white/50 bg-white/40 text-slate-700 shadow-sm outline-none backdrop-blur transition hover:bg-white/70 focus-visible:ring-2 focus-visible:ring-indigo-500/70 focus-visible:ring-offset-2 focus-visible:ring-offset-transparent active:scale-95 dark:border-white/10 dark:bg-white/10 dark:text-slate-200 dark:hover:bg-white/20"
>
{copied ? (
<svg viewBox="0 0 24 24" className="h-4 w-4 text-emerald-500" fill="none" stroke="currentColor" strokeWidth={2.4} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
<path d="M20 6 9 17l-5-5" />
</svg>
) : (
<svg viewBox="0 0 24 24" className="h-4 w-4" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
<rect x="9" y="9" width="11" height="11" rx="2" />
<path d="M5 15V5a2 2 0 0 1 2-2h10" />
</svg>
)}
</button>
);
}
type LikeButtonProps = {
count: number;
};
function LikeButton({ count }: LikeButtonProps) {
const [liked, setLiked] = useState(false);
const reduce = useReducedMotion();
return (
<button
type="button"
aria-pressed={liked}
aria-label={liked ? "Remove from favorites" : "Add to favorites"}
onClick={() => setLiked((v) => !v)}
className="inline-flex items-center gap-1.5 rounded-full border border-white/50 bg-white/40 px-3 py-1.5 text-sm font-medium text-slate-700 shadow-sm outline-none backdrop-blur transition hover:bg-white/70 focus-visible:ring-2 focus-visible:ring-rose-500/70 focus-visible:ring-offset-2 focus-visible:ring-offset-transparent active:scale-95 dark:border-white/10 dark:bg-white/10 dark:text-slate-200 dark:hover:bg-white/20"
>
<motion.span
key={liked ? "on" : "off"}
initial={reduce ? false : { scale: 0.6 }}
animate={reduce ? {} : { scale: 1 }}
transition={{ type: "spring", stiffness: 500, damping: 18 }}
className="inline-flex"
>
<svg
viewBox="0 0 24 24"
className={`h-4 w-4 transition-colors ${liked ? "text-rose-500" : "text-slate-500 dark:text-slate-400"}`}
fill={liked ? "currentColor" : "none"}
stroke="currentColor"
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
>
<path d="M20.8 4.6a5.5 5.5 0 0 0-7.8 0L12 5.6l-1-1a5.5 5.5 0 1 0-7.8 7.8l1 1L12 21l7.8-7.6 1-1a5.5 5.5 0 0 0 0-7.8Z" />
</svg>
</motion.span>
<span className="tabular-nums">{count + (liked ? 1 : 0)}</span>
</button>
);
}
type Plan = "monthly" | "annual";
export default function CardGlass() {
const reduce = useReducedMotion();
const [plan, setPlan] = useState<Plan>("annual");
const [expanded, setExpanded] = useState(false);
const detailsId = useId();
const price = plan === "annual" ? 24 : 29;
return (
<section className="cg-scope relative w-full overflow-hidden px-5 py-20 sm:py-28">
<style>{`
@keyframes cg-drift {
0%, 100% { transform: translate3d(0,0,0) scale(1); }
50% { transform: translate3d(4%, -3%, 0) scale(1.08); }
}
@keyframes cg-sheen {
0% { transform: translateX(-120%); }
60%, 100% { transform: translateX(220%); }
}
.cg-scope .cg-blob { animation: cg-drift 18s ease-in-out infinite; }
.cg-scope .cg-blob-2 { animation-duration: 24s; animation-direction: reverse; }
.cg-scope .cg-blob-3 { animation-duration: 30s; }
.cg-scope .cg-card:hover .cg-sheen { animation: cg-sheen 1.1s ease-out; }
@media (prefers-reduced-motion: reduce) {
.cg-scope .cg-blob,
.cg-scope .cg-card:hover .cg-sheen { animation: none !important; }
}
`}</style>
{/* Soft gradient backdrop */}
<div className="pointer-events-none absolute inset-0 -z-10 bg-gradient-to-br from-sky-100 via-violet-100 to-rose-100 dark:from-slate-950 dark:via-indigo-950 dark:to-slate-900" />
<div className="pointer-events-none absolute inset-0 -z-10 overflow-hidden">
<div className="cg-blob absolute -left-24 top-4 h-80 w-80 rounded-full bg-indigo-400/40 blur-3xl dark:bg-indigo-500/25" />
<div className="cg-blob cg-blob-2 absolute right-0 top-24 h-96 w-96 rounded-full bg-rose-400/40 blur-3xl dark:bg-fuchsia-500/20" />
<div className="cg-blob cg-blob-3 absolute bottom-0 left-1/3 h-80 w-80 rounded-full bg-sky-400/40 blur-3xl dark:bg-sky-500/20" />
</div>
<div className="mx-auto max-w-6xl">
<header className="mx-auto mb-14 max-w-2xl text-center">
<span className="inline-flex items-center gap-2 rounded-full border border-white/50 bg-white/40 px-3 py-1 text-xs font-medium uppercase tracking-wider text-slate-600 backdrop-blur dark:border-white/10 dark:bg-white/5 dark:text-slate-300">
<span className="h-1.5 w-1.5 rounded-full bg-indigo-500" />
Glass UI
</span>
<h2 className="mt-4 text-balance text-3xl font-semibold tracking-tight text-slate-900 dark:text-white sm:text-4xl">
Frosted glass cards
</h2>
<p className="mt-3 text-pretty text-base text-slate-600 dark:text-slate-300">
Translucent surfaces layered over a soft, drifting gradient. Blur, a
hairline highlight, and a passing sheen on hover.
</p>
</header>
<div className="grid grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
{/* Card 1 — Product with photo */}
<article className="cg-card group relative overflow-hidden rounded-3xl border border-white/50 bg-white/45 p-4 shadow-[0_8px_40px_-12px_rgba(30,41,59,0.35)] backdrop-blur-2xl transition-transform duration-300 hover:-translate-y-1 dark:border-white/10 dark:bg-white/[0.06]">
<span className="pointer-events-none absolute inset-x-0 top-0 h-px bg-gradient-to-r from-transparent via-white/80 to-transparent dark:via-white/30" />
<div className="cg-sheen pointer-events-none absolute inset-y-0 -left-1/2 w-1/2 -skew-x-12 bg-gradient-to-r from-transparent via-white/50 to-transparent dark:via-white/10" />
<div className="relative overflow-hidden rounded-2xl">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src="/img/gallery/g07.webp"
alt="Aurora Studio wireless over-ear headphones in graphite"
loading="lazy"
draggable={false}
className="h-44 w-full object-cover"
/>
<div className="absolute left-3 top-3 rounded-full border border-white/40 bg-white/50 px-2.5 py-1 text-xs font-semibold text-slate-800 backdrop-blur dark:border-white/10 dark:bg-black/30 dark:text-white">
New
</div>
</div>
<div className="relative mt-4 px-1">
<div className="flex items-start justify-between gap-3">
<div>
<h3 className="text-lg font-semibold text-slate-900 dark:text-white">
Aurora Studio
</h3>
<p className="text-sm text-slate-600 dark:text-slate-300">
Adaptive noise-cancelling headphones
</p>
</div>
<p className="whitespace-nowrap text-lg font-semibold text-slate-900 dark:text-white">
$349
</p>
</div>
<div className="mt-5 flex items-center justify-between">
<LikeButton count={128} />
<div className="flex items-center gap-2">
<CopyButton value="https://shop.example.com/aurora-studio" label="Copy product link" />
<button
type="button"
className="inline-flex items-center gap-1.5 rounded-full bg-slate-900 px-4 py-2 text-sm font-semibold text-white shadow-sm outline-none transition hover:bg-slate-800 focus-visible:ring-2 focus-visible:ring-indigo-500/70 focus-visible:ring-offset-2 focus-visible:ring-offset-transparent active:scale-95 dark:bg-white dark:text-slate-900 dark:hover:bg-slate-100"
>
Add
</button>
</div>
</div>
</div>
</article>
{/* Card 2 — Pricing with real toggle */}
<article className="cg-card group relative overflow-hidden rounded-3xl border border-white/50 bg-white/45 p-6 shadow-[0_8px_40px_-12px_rgba(30,41,59,0.35)] backdrop-blur-2xl transition-transform duration-300 hover:-translate-y-1 dark:border-white/10 dark:bg-white/[0.06]">
<span className="pointer-events-none absolute inset-x-0 top-0 h-px bg-gradient-to-r from-transparent via-white/80 to-transparent dark:via-white/30" />
<div className="cg-sheen pointer-events-none absolute inset-y-0 -left-1/2 w-1/2 -skew-x-12 bg-gradient-to-r from-transparent via-white/50 to-transparent dark:via-white/10" />
<div className="relative">
<div className="flex items-center justify-between">
<h3 className="text-lg font-semibold text-slate-900 dark:text-white">
Pro plan
</h3>
<span className="rounded-full border border-indigo-300/50 bg-indigo-500/10 px-2.5 py-1 text-xs font-semibold text-indigo-700 dark:border-indigo-400/30 dark:text-indigo-300">
Save 17%
</span>
</div>
<div
role="group"
aria-label="Billing period"
className="mt-4 inline-flex rounded-full border border-white/50 bg-white/40 p-1 backdrop-blur dark:border-white/10 dark:bg-white/10"
>
{(["monthly", "annual"] as const).map((option) => {
const active = plan === option;
return (
<button
key={option}
type="button"
aria-pressed={active}
onClick={() => setPlan(option)}
className={`rounded-full px-4 py-1.5 text-sm font-medium capitalize outline-none transition focus-visible:ring-2 focus-visible:ring-indigo-500/70 focus-visible:ring-offset-1 focus-visible:ring-offset-transparent ${
active
? "bg-slate-900 text-white shadow-sm dark:bg-white dark:text-slate-900"
: "text-slate-600 hover:text-slate-900 dark:text-slate-300 dark:hover:text-white"
}`}
>
{option}
</button>
);
})}
</div>
<div className="mt-6 flex items-end gap-1">
<motion.span
key={price}
initial={reduce ? false : { y: 8, opacity: 0 }}
animate={reduce ? {} : { y: 0, opacity: 1 }}
transition={{ duration: 0.25, ease: "easeOut" }}
className="text-5xl font-semibold tracking-tight text-slate-900 dark:text-white"
>
${price}
</motion.span>
<span className="mb-1.5 text-sm text-slate-500 dark:text-slate-400">
/ user / mo
</span>
</div>
<ul className="mt-5 space-y-2.5 text-sm text-slate-700 dark:text-slate-300">
{["Unlimited projects", "Advanced analytics", "Priority support"].map((f) => (
<li key={f} className="flex items-center gap-2.5">
<svg viewBox="0 0 24 24" className="h-4 w-4 shrink-0 text-emerald-500" fill="none" stroke="currentColor" strokeWidth={2.4} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
<path d="M20 6 9 17l-5-5" />
</svg>
{f}
</li>
))}
</ul>
<button
type="button"
className="mt-6 w-full rounded-2xl bg-gradient-to-r from-indigo-500 to-violet-500 px-4 py-2.5 text-sm font-semibold text-white shadow-lg shadow-indigo-500/25 outline-none transition hover:from-indigo-600 hover:to-violet-600 focus-visible:ring-2 focus-visible:ring-indigo-500/70 focus-visible:ring-offset-2 focus-visible:ring-offset-transparent active:scale-[0.98]"
>
Start free trial
</button>
</div>
</article>
{/* Card 3 — Profile with expandable bio */}
<article className="cg-card group relative overflow-hidden rounded-3xl border border-white/50 bg-white/45 p-6 shadow-[0_8px_40px_-12px_rgba(30,41,59,0.35)] backdrop-blur-2xl transition-transform duration-300 hover:-translate-y-1 dark:border-white/10 dark:bg-white/[0.06]">
<span className="pointer-events-none absolute inset-x-0 top-0 h-px bg-gradient-to-r from-transparent via-white/80 to-transparent dark:via-white/30" />
<div className="cg-sheen pointer-events-none absolute inset-y-0 -left-1/2 w-1/2 -skew-x-12 bg-gradient-to-r from-transparent via-white/50 to-transparent dark:via-white/10" />
<div className="relative">
<div className="flex items-center gap-4">
<div className="relative h-16 w-16 shrink-0 overflow-hidden rounded-2xl ring-2 ring-white/60 dark:ring-white/10">
{/* eslint-disable-next-line @next/next/no-img-element */}
<img
src="/img/gallery/g19.webp"
alt="Portrait of Priya Nair"
loading="lazy"
draggable={false}
className="h-full w-full object-cover"
/>
</div>
<div>
<h3 className="text-lg font-semibold text-slate-900 dark:text-white">
Priya Nair
</h3>
<p className="text-sm text-slate-600 dark:text-slate-300">
Head of Design, Northwind
</p>
</div>
</div>
<p className="mt-4 text-sm leading-relaxed text-slate-700 dark:text-slate-300">
“The frosted panels shipped in a day and lifted trial
sign-ups by 12%.”
</p>
<AnimatePresence initial={false}>
{expanded && (
<motion.div
id={detailsId}
key="details"
initial={reduce ? { opacity: 0 } : { height: 0, opacity: 0 }}
animate={reduce ? { opacity: 1 } : { height: "auto", opacity: 1 }}
exit={reduce ? { opacity: 0 } : { height: 0, opacity: 0 }}
transition={{ duration: 0.28, ease: "easeInOut" }}
className="overflow-hidden"
>
<p className="pt-3 text-sm leading-relaxed text-slate-600 dark:text-slate-400">
Priya leads a team of nine across Bengaluru and Berlin.
Before Northwind she built the design system at Loop and
spoke on glassmorphism at Config 2025.
</p>
</motion.div>
)}
</AnimatePresence>
<div className="mt-5 flex items-center justify-between">
<button
type="button"
aria-expanded={expanded}
aria-controls={detailsId}
onClick={() => setExpanded((v) => !v)}
className="inline-flex items-center gap-1.5 text-sm font-semibold text-indigo-700 outline-none transition hover:text-indigo-800 focus-visible:ring-2 focus-visible:ring-indigo-500/70 focus-visible:ring-offset-2 focus-visible:ring-offset-transparent dark:text-indigo-300 dark:hover:text-indigo-200"
>
{expanded ? "Show less" : "Read more"}
<svg viewBox="0 0 24 24" className={`h-4 w-4 transition-transform ${expanded ? "rotate-180" : ""}`} fill="none" stroke="currentColor" strokeWidth={2.2} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
<path d="m6 9 6 6 6-6" />
</svg>
</button>
<div className="flex items-center gap-2">
<a
href="https://www.linkedin.com/"
target="_blank"
rel="noopener"
aria-label="Priya Nair on LinkedIn"
className="inline-flex h-9 w-9 items-center justify-center rounded-full border border-white/50 bg-white/40 text-slate-700 shadow-sm outline-none backdrop-blur transition hover:bg-white/70 focus-visible:ring-2 focus-visible:ring-sky-500/70 focus-visible:ring-offset-2 focus-visible:ring-offset-transparent active:scale-95 dark:border-white/10 dark:bg-white/10 dark:text-slate-200 dark:hover:bg-white/20"
>
<svg viewBox="0 0 24 24" className="h-4 w-4" fill="currentColor" aria-hidden="true">
<path d="M4.98 3.5A2.5 2.5 0 1 1 5 8.5a2.5 2.5 0 0 1-.02-5ZM3 9h4v12H3V9Zm6 0h3.8v1.7h.05c.53-1 1.83-2.05 3.76-2.05C20.4 8.65 22 10.7 22 14v7h-4v-6.2c0-1.48-.03-3.38-2.06-3.38-2.06 0-2.38 1.6-2.38 3.27V21H9V9Z" />
</svg>
</a>
<LikeButton count={64} />
</div>
</div>
</div>
</article>
</div>
</div>
</section>
);
}Dependencies
Licence
Built by Web Innoventix. Free for personal and commercial use, no attribution required.
Built by Web Innoventix
Need a custom interface, a full website, or SEO that gets you cited by AI? We design, build and rank it end to end.
Get a free quoteSimilar components
Browse all →
3D Tilt Cards
OriginalA responsive grid of cards that tilt in 3D toward your cursor with a light glare and lifted depth layers, powered by Framer Motion springs.

Spotlight Follow Cards
OriginalFeature cards where a soft radial spotlight and a glowing border chase the cursor on hover, with a staggered scroll reveal and an animated shimmer line.

3D Flip Cards
OriginalPricing-style cards that flip in 3D on hover or tap to reveal details on the back, keyboard accessible with a staggered entrance animation.

Animated Gradient Border Cards
OriginalCards wrapped in a live conic gradient border that rotates and speeds up on hover, with a shimmer sweep and a scrolling tag marquee.

Glow Effect Card
primitivesA reusable glow effect card for React and Tailwind, with hover and motion.

Neon Gradient Card
gradient-card.tsxA reusable neon gradient card for React and Tailwind, with hover and motion.

Spotlight Magic Card
card.tsxA reusable spotlight magic card for React and Tailwind, with hover and motion.

Tilt Spotlight Card
primitivesA reusable tilt spotlight card for React and Tailwind, with hover and motion.

Profile Card
OriginalA user profile card with avatar, stats and a follow toggle.

Product Card
OriginalA product card with image, price and add-to-cart feedback.

Pricing Single Card
OriginalA single pricing plan card with feature list and CTA.

Stat Card
OriginalA metric card with value, trend arrow and a small sparkline.

