UI Components Easy
Glassmorphism Card
A frosted-glass card effect using CSS backdrop-filter, subtle borders, and layered transparency.
Open in Lab
MCP
css backdrop-filter vue svelte
Targets: TS JS HTML React Vue Svelte
Code
*,
*::before,
*::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: system-ui, -apple-system, sans-serif;
min-height: 100vh;
display: grid;
place-items: center;
background: #0f172a;
}
/* Gradient background blobs */
.bg {
width: 100%;
min-height: 100vh;
display: grid;
place-items: center;
background: radial-gradient(
ellipse 600px 400px at 20% 30%,
rgba(56, 189, 248, 0.25) 0%,
transparent 70%
), radial-gradient(ellipse 500px 350px at 80% 70%, rgba(168, 85, 247, 0.25) 0%, transparent 70%),
#0f172a;
}
/* --- Glass card --- */
.glass-card {
width: min(380px, calc(100vw - 2rem));
padding: 2.5rem;
border-radius: 1.5rem;
/* Glass effect */
background: rgba(255, 255, 255, 0.06);
backdrop-filter: blur(16px) saturate(1.6);
-webkit-backdrop-filter: blur(16px) saturate(1.6);
border: 1px solid rgba(255, 255, 255, 0.12);
box-shadow: 0 4px 32px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.1);
display: flex;
flex-direction: column;
gap: 1rem;
color: #f1f5f9;
}
.card-icon {
font-size: 1.75rem;
line-height: 1;
color: #38bdf8;
}
.card-title {
font-size: 1.375rem;
font-weight: 700;
letter-spacing: -0.02em;
}
.card-body {
font-size: 0.9375rem;
line-height: 1.65;
color: #94a3b8;
}
.card-body code {
font-family: "Fira Code", monospace;
font-size: 0.85em;
background: rgba(255, 255, 255, 0.08);
padding: 0.1em 0.4em;
border-radius: 0.3em;
color: #a5b4fc;
}
.card-tags {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.tag {
font-size: 0.75rem;
font-weight: 500;
padding: 0.25rem 0.75rem;
border-radius: 999px;
background: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(255, 255, 255, 0.12);
color: #cbd5e1;
letter-spacing: 0.02em;
}
.card-btn {
margin-top: 0.5rem;
align-self: flex-start;
font-size: 0.875rem;
font-weight: 600;
padding: 0.625rem 1.25rem;
border-radius: 0.75rem;
border: 1px solid rgba(56, 189, 248, 0.4);
background: rgba(56, 189, 248, 0.12);
color: #38bdf8;
cursor: pointer;
transition: background 0.2s ease, border-color 0.2s ease, transform 0.15s ease;
}
.card-btn:hover {
background: rgba(56, 189, 248, 0.22);
border-color: rgba(56, 189, 248, 0.6);
transform: translateY(-1px);
}
.card-btn:active {
transform: translateY(0);
}// Glassmorphism Card — no JS required for the base effect.
// This script adds an optional mouse-tracking shine effect.
(function () {
"use strict";
const card = document.querySelector(".glass-card");
if (!card) return;
card.addEventListener("mousemove", (e) => {
const rect = card.getBoundingClientRect();
const x = ((e.clientX - rect.left) / rect.width) * 100;
const y = ((e.clientY - rect.top) / rect.height) * 100;
card.style.setProperty("--shine-x", `${x}%`);
card.style.setProperty("--shine-y", `${y}%`);
const rotateX = ((e.clientY - rect.top) / rect.height - 0.5) * -6;
const rotateY = ((e.clientX - rect.left) / rect.width - 0.5) * 6;
card.style.transform = `perspective(800px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`;
});
card.addEventListener("mouseleave", () => {
card.style.transform = "";
});
})();<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Glassmorphism Card</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="bg">
<div class="glass-card">
<div class="card-icon">✦</div>
<h2 class="card-title">Glassmorphism</h2>
<p class="card-body">
A frosted-glass card effect using CSS <code>backdrop-filter</code>,
subtle borders, and layered transparency.
</p>
<div class="card-tags">
<span class="tag">CSS</span>
<span class="tag">backdrop-filter</span>
<span class="tag">UI</span>
</div>
<button class="card-btn">Steal This →</button>
</div>
</div>
<link rel="stylesheet" href="style.css" />
</body>
</html>import { useRef } from "react";
interface GlassCardProps {
icon?: string;
title: string;
body: string;
tags?: string[];
cta?: string;
onCtaClick?: () => void;
}
export function GlassCard({
icon = "✦",
title,
body,
tags = [],
cta = "Steal This →",
onCtaClick,
}: GlassCardProps) {
const cardRef = useRef<HTMLDivElement>(null);
function handleMouseMove(e: React.MouseEvent<HTMLDivElement>) {
const card = cardRef.current;
if (!card) return;
const rect = card.getBoundingClientRect();
const rotateX = ((e.clientY - rect.top) / rect.height - 0.5) * -6;
const rotateY = ((e.clientX - rect.left) / rect.width - 0.5) * 6;
card.style.transform = `perspective(800px) rotateX(${rotateX}deg) rotateY(${rotateY}deg)`;
}
function handleMouseLeave() {
const card = cardRef.current;
if (card) card.style.transform = "";
}
return (
<div
ref={cardRef}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
style={{ transition: "transform 0.1s ease" }}
className="
w-full max-w-sm p-10 rounded-3xl flex flex-col gap-4
text-slate-100
border border-white/10
shadow-[0_4px_32px_rgba(0,0,0,0.2),inset_0_1px_0_rgba(255,255,255,0.1)]
"
// Tailwind doesn't support backdrop-filter class by default in all setups,
// so we use inline style for the glass effect
style={{
background: "rgba(255,255,255,0.06)",
backdropFilter: "blur(16px) saturate(1.6)",
WebkitBackdropFilter: "blur(16px) saturate(1.6)",
transition: "transform 0.1s ease",
}}
>
<span className="text-3xl text-sky-400">{icon}</span>
<h2 className="text-xl font-bold tracking-tight">{title}</h2>
<p className="text-slate-400 text-sm leading-relaxed">{body}</p>
{tags.length > 0 && (
<div className="flex flex-wrap gap-2">
{tags.map((tag) => (
<span
key={tag}
className="text-xs font-medium px-3 py-1 rounded-full bg-white/8 border border-white/10 text-slate-300"
>
{tag}
</span>
))}
</div>
)}
{cta && (
<button
type="button"
onClick={onCtaClick}
className="mt-2 self-start text-sm font-semibold px-5 py-2.5 rounded-xl
bg-sky-400/10 border border-sky-400/40 text-sky-400
hover:bg-sky-400/20 hover:border-sky-400/60
transition-colors duration-200 active:scale-95"
>
{cta}
</button>
)}
</div>
);
}
// Demo usage
export default function GlassCardDemo() {
return (
<div
className="min-h-screen grid place-items-center"
style={{
background:
"radial-gradient(ellipse 600px 400px at 20% 30%, rgba(56,189,248,0.25) 0%, transparent 70%), radial-gradient(ellipse 500px 350px at 80% 70%, rgba(168,85,247,0.25) 0%, transparent 70%), #0f172a",
}}
>
<GlassCard
title="Glassmorphism"
body="A frosted-glass card effect using CSS backdrop-filter, subtle borders, and layered transparency."
tags={["CSS", "backdrop-filter", "UI"]}
onCtaClick={() => navigator.clipboard.writeText("GlassCard snippet copied!")}
/>
</div>
);
}<script setup>
import { ref } from "vue";
const cardEl = ref(null);
function handleMove(e) {
if (!cardEl.value) return;
const rect = cardEl.value.getBoundingClientRect();
const rx = ((e.clientY - rect.top) / rect.height - 0.5) * -6;
const ry = ((e.clientX - rect.left) / rect.width - 0.5) * 6;
cardEl.value.style.transform = `perspective(800px) rotateX(${rx}deg) rotateY(${ry}deg)`;
}
function handleLeave() {
if (cardEl.value) cardEl.value.style.transform = "";
}
const tags = ["CSS", "backdrop-filter", "UI"];
</script>
<template>
<div class="min-h-screen grid place-items-center" style="background:radial-gradient(ellipse 600px 400px at 20% 30%,rgba(56,189,248,0.25) 0%,transparent 70%),radial-gradient(ellipse 500px 350px at 80% 70%,rgba(168,85,247,0.25) 0%,transparent 70%),#0f172a">
<div ref="cardEl" @mousemove="handleMove" @mouseleave="handleLeave" class="w-full max-w-sm p-10 rounded-3xl flex flex-col gap-4 text-slate-100 border border-white/10" style="background:rgba(255,255,255,0.06);backdrop-filter:blur(16px) saturate(1.6);-webkit-backdrop-filter:blur(16px) saturate(1.6);transition:transform 0.1s ease;box-shadow:0 4px 32px rgba(0,0,0,0.2),inset 0 1px 0 rgba(255,255,255,0.1)">
<span class="text-3xl text-sky-400">✦</span>
<h2 class="text-xl font-bold tracking-tight">Glassmorphism</h2>
<p class="text-slate-400 text-sm leading-relaxed">A frosted-glass card effect using CSS backdrop-filter, subtle borders, and layered transparency.</p>
<div class="flex flex-wrap gap-2">
<span v-for="tag in tags" :key="tag" class="text-xs font-medium px-3 py-1 rounded-full bg-white/[0.08] border border-white/10 text-slate-300">{{ tag }}</span>
</div>
<button class="mt-2 self-start text-sm font-semibold px-5 py-2.5 rounded-xl bg-sky-400/10 border border-sky-400/40 text-sky-400 hover:bg-sky-400/20 hover:border-sky-400/60 transition-colors duration-200 active:scale-95">Steal This →</button>
</div>
</div>
</template><script>
let cardEl;
function handleMove(e) {
if (!cardEl) return;
const rect = cardEl.getBoundingClientRect();
const rx = ((e.clientY - rect.top) / rect.height - 0.5) * -6;
const ry = ((e.clientX - rect.left) / rect.width - 0.5) * 6;
cardEl.style.transform = `perspective(800px) rotateX(${rx}deg) rotateY(${ry}deg)`;
}
function handleLeave() {
if (cardEl) cardEl.style.transform = "";
}
</script>
<div class="min-h-screen grid place-items-center" style="background:radial-gradient(ellipse 600px 400px at 20% 30%,rgba(56,189,248,0.25) 0%,transparent 70%),radial-gradient(ellipse 500px 350px at 80% 70%,rgba(168,85,247,0.25) 0%,transparent 70%),#0f172a">
<div bind:this={cardEl} on:mousemove={handleMove} on:mouseleave={handleLeave} class="w-full max-w-sm p-10 rounded-3xl flex flex-col gap-4 text-slate-100 border border-white/10" style="background:rgba(255,255,255,0.06);backdrop-filter:blur(16px) saturate(1.6);-webkit-backdrop-filter:blur(16px) saturate(1.6);transition:transform 0.1s ease;box-shadow:0 4px 32px rgba(0,0,0,0.2),inset 0 1px 0 rgba(255,255,255,0.1)">
<span class="text-3xl text-sky-400">✦</span>
<h2 class="text-xl font-bold tracking-tight">Glassmorphism</h2>
<p class="text-slate-400 text-sm leading-relaxed">A frosted-glass card effect using CSS backdrop-filter, subtle borders, and layered transparency.</p>
<div class="flex flex-wrap gap-2">
{#each ["CSS", "backdrop-filter", "UI"] as tag}
<span class="text-xs font-medium px-3 py-1 rounded-full bg-white/[0.08] border border-white/10 text-slate-300">{tag}</span>
{/each}
</div>
<button class="mt-2 self-start text-sm font-semibold px-5 py-2.5 rounded-xl bg-sky-400/10 border border-sky-400/40 text-sky-400 hover:bg-sky-400/20 hover:border-sky-400/60 transition-colors duration-200 active:scale-95">Steal This →</button>
</div>
</div>Glassmorphism Card
A modern glassmorphism card component using backdrop-filter: blur() for a frosted-glass appearance, combined with semi-transparent backgrounds and soft borders.
How it works
The effect relies on three CSS properties working together:
backdrop-filter: blur(12px)— blurs content behind the cardbackground: rgba(255,255,255,0.08)— semi-transparent backgroundborder: 1px solid rgba(255,255,255,0.12)— subtle light border
Browser support
backdrop-filter is supported in all modern browsers. For Firefox, prefix with -webkit-backdrop-filter for older versions.
When to use it
- Feature cards on dark/gradient backgrounds
- Modal dialogs over blurred content
- Navigation panels with transparent feel