18 / 20
All 20 in 20 Tailwind CSS Popovers
- 01Tailwind Popover Show and Hide with the Popover API
- 02Tailwind Auto vs Manual Popover Behavior
- 03Tailwind Anchored Popover with CSS Anchor Positioning
- 04Tailwind Popover Entry and Exit Animation
- 05Tailwind Popover Backdrop and Light Dismiss
- 06Tailwind Position Area Popover Placement Grid
- 07Tailwind Popover Flip with Position Try Fallbacks
- 08Tailwind Tooltip Arrow Pointing to Anchor
- 09Tailwind Dropdown Matching Anchor Width
- 10Tailwind Nested Popover Submenu
- 11Tailwind Custom Select Listbox Popover
- 12Tailwind Tooltip on Hover and Focus
- 13Tailwind User Profile Dropdown Menu
- 14Tailwind Date Picker Popover
- 15Tailwind Filter Dropdown with Checkboxes
- 16Tailwind Popover Fallback and Polyfill
- 17Tailwind Popover vs Dialog Modal
- 18Tailwind Glassmorphism Popover
- 19Tailwind Dark Mode Popover Toggle
- 20Tailwind Accessible Tooltip with ARIA
Tailwind Glassmorphism Popover
A frosted panel over a rich aurora, with the opaque fallback as the base class and the frost layered on with supports-[backdrop-filter:blur(1px)]: — so an unsupporting engine shows a solid card, never text over raw colour. Because the panel lives in the top layer it has no transformed ancestor to become its backdrop root: the blur samples the real page.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tpop-18 group/root w-full min-h-svh bg-tpop18-night bg-[radial-gradient(46rem_30rem_at_12%_8%,var(--color-tpop18-violet),transparent_62%),radial-gradient(38rem_26rem_at_88%_22%,var(--color-tpop18-teal),transparent_60%),radial-gradient(34rem_28rem_at_62%_92%,var(--color-tpop18-rose),transparent_58%)] px-4.5 py-10 font-tpop18-sans text-tpop18-ink" aria-label="Glassmorphism popover demo">
<div class="grid min-h-[calc(100svh-80px)] max-w-full place-items-center">
<div class="w-full min-w-0 max-w-[28rem]">
<div aria-hidden="true" class="mb-6 size-28 rounded-3xl bg-[conic-gradient(from_210deg,var(--color-tpop18-rose),var(--color-tpop18-violet),var(--color-tpop18-teal),var(--color-tpop18-rose))] shadow-[0_24px_50px_-18px_oklch(0_0_0/0.7),inset_0_1px_0_oklch(1_0_0/0.3)]"></div>
<p class="mb-2.5 text-[10.5px] font-bold uppercase tracking-[0.24em] text-tpop18-mut">Now playing</p>
<h2 class="mb-1.5 text-[clamp(34px,8vw,52px)] font-bold leading-[0.98] tracking-[-0.035em]">Wickfield No. 5</h2>
<p class="mb-5 text-[15px] text-tpop18-mut">Marisa Ault · Slow Water · 2026</p>
<div class="mb-5 flex items-center gap-3 font-tpop18-mono text-[11.5px] text-tpop18-mut">
<span class="tabular-nums">2:14</span>
<span class="h-1 flex-auto overflow-hidden rounded-full bg-white/15"><span class="block h-full w-1/3 rounded-full bg-tpop18-ink"></span></span>
<span class="tabular-nums">6:41</span>
</div>
<button id="tpop-18-trigger" type="button" popovertarget="tpop-18-panel" aria-label="Track details" class="inline-flex size-11 cursor-pointer items-center justify-center rounded-full border border-white/30 bg-white/12 text-tpop18-ink transition-[background-color,box-shadow] duration-200 [anchor-name:--tpop18-a] hover:bg-white/20 focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-tpop18-ink group-has-[#tpop-18-panel:popover-open]/root:bg-white/25 group-has-[#tpop-18-panel:popover-open]/root:shadow-[0_0_24px_oklch(1_0_0/0.35)]">
<svg viewBox="0 0 22 22" width="19" height="19" fill="none" stroke="currentColor" stroke-width="1.7" aria-hidden="true"><circle cx="11" cy="11" r="8"/><path d="M11 10v5.4M11 7.2v.9"/></svg>
</button>
<p class="mt-5 max-w-[24rem] text-[13px] leading-relaxed text-tpop18-mut text-pretty">Open the panel: it blurs the top layer's view of this page, not a mocked-up copy of it.</p>
</div>
</div>
<div popover="auto" id="tpop-18-panel" role="group" aria-label="Track details" class="fixed m-auto w-[min(18rem,calc(100vw-28px))] rounded-3xl border border-white/30 bg-tpop18-glass p-4.5 text-tpop18-ink opacity-0 translate-y-1.5 shadow-[0_26px_60px_-28px_oklch(0_0_0/0.8),inset_0_1px_0_oklch(1_0_0/0.22)] transition-[opacity,translate,display,overlay] duration-200 ease-out transition-discrete [position-anchor:--tpop18-a] [position-area:block-end_span-inline-end] [position-try-fallbacks:flip-block,flip-inline] open:translate-y-0 open:opacity-100 starting:open:translate-y-1.5 starting:open:opacity-0 motion-reduce:transition-none supports-[anchor-name:--a]:inset-auto supports-[anchor-name:--a]:m-0 supports-[anchor-name:--a]:mt-2.5 supports-[backdrop-filter:blur(1px)]:bg-tpop18-glass/55 supports-[backdrop-filter:blur(1px)]:backdrop-blur-[18px] supports-[backdrop-filter:blur(1px)]:backdrop-saturate-150">
<p class="mb-3 text-[10.5px] font-bold uppercase tracking-[0.2em] text-tpop18-mut">Track details</p>
<dl class="grid gap-2">
<div class="flex min-w-0 justify-between gap-3"><dt class="text-[13px] text-tpop18-mut">Length</dt><dd class="font-tpop18-mono text-[13px] font-semibold">6:41</dd></div>
<div class="flex min-w-0 justify-between gap-3"><dt class="text-[13px] text-tpop18-mut">Key</dt><dd class="text-[13px] font-semibold">D minor</dd></div>
<div class="flex min-w-0 justify-between gap-3"><dt class="text-[13px] text-tpop18-mut">Tempo</dt><dd class="font-tpop18-mono text-[13px] font-semibold">72 bpm</dd></div>
<div class="flex min-w-0 justify-between gap-3"><dt class="text-[13px] text-tpop18-mut">Mastered</dt><dd class="text-[13px] font-semibold">Alex Chen</dd></div>
</dl>
<p class="mt-3.5 border-t border-white/16 pt-3 text-xs text-tpop18-mut">Opaque fallback first, frost second.</p>
</div>
</section><section class="tpop-18 group/root w-full min-h-svh bg-tpop18-night bg-[radial-gradient(46rem_30rem_at_12%_8%,var(--color-tpop18-violet),transparent_62%),radial-gradient(38rem_26rem_at_88%_22%,var(--color-tpop18-teal),transparent_60%),radial-gradient(34rem_28rem_at_62%_92%,var(--color-tpop18-rose),transparent_58%)] px-4.5 py-10 font-tpop18-sans text-tpop18-ink" aria-label="Glassmorphism popover demo">
<div class="grid min-h-[calc(100svh-80px)] max-w-full place-items-center">
<div class="w-full min-w-0 max-w-[28rem]">
<div aria-hidden="true" class="mb-6 size-28 rounded-3xl bg-[conic-gradient(from_210deg,var(--color-tpop18-rose),var(--color-tpop18-violet),var(--color-tpop18-teal),var(--color-tpop18-rose))] shadow-[0_24px_50px_-18px_oklch(0_0_0/0.7),inset_0_1px_0_oklch(1_0_0/0.3)]"></div>
<p class="mb-2.5 text-[10.5px] font-bold uppercase tracking-[0.24em] text-tpop18-mut">Now playing</p>
<h2 class="mb-1.5 text-[clamp(34px,8vw,52px)] font-bold leading-[0.98] tracking-[-0.035em]">Wickfield No. 5</h2>
<p class="mb-5 text-[15px] text-tpop18-mut">Marisa Ault · Slow Water · 2026</p>
<div class="mb-5 flex items-center gap-3 font-tpop18-mono text-[11.5px] text-tpop18-mut">
<span class="tabular-nums">2:14</span>
<span class="h-1 flex-auto overflow-hidden rounded-full bg-white/15"><span class="block h-full w-1/3 rounded-full bg-tpop18-ink"></span></span>
<span class="tabular-nums">6:41</span>
</div>
<button id="tpop-18-trigger" type="button" popovertarget="tpop-18-panel" aria-label="Track details" class="inline-flex size-11 cursor-pointer items-center justify-center rounded-full border border-white/30 bg-white/12 text-tpop18-ink transition-[background-color,box-shadow] duration-200 [anchor-name:--tpop18-a] hover:bg-white/20 focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-tpop18-ink group-has-[#tpop-18-panel:popover-open]/root:bg-white/25 group-has-[#tpop-18-panel:popover-open]/root:shadow-[0_0_24px_oklch(1_0_0/0.35)]">
<svg viewBox="0 0 22 22" width="19" height="19" fill="none" stroke="currentColor" stroke-width="1.7" aria-hidden="true"><circle cx="11" cy="11" r="8"/><path d="M11 10v5.4M11 7.2v.9"/></svg>
</button>
<p class="mt-5 max-w-[24rem] text-[13px] leading-relaxed text-tpop18-mut text-pretty">Open the panel: it blurs the top layer's view of this page, not a mocked-up copy of it.</p>
</div>
</div>
<div popover="auto" id="tpop-18-panel" role="group" aria-label="Track details" class="fixed m-auto w-[min(18rem,calc(100vw-28px))] rounded-3xl border border-white/30 bg-tpop18-glass p-4.5 text-tpop18-ink opacity-0 translate-y-1.5 shadow-[0_26px_60px_-28px_oklch(0_0_0/0.8),inset_0_1px_0_oklch(1_0_0/0.22)] transition-[opacity,translate,display,overlay] duration-200 ease-out transition-discrete [position-anchor:--tpop18-a] [position-area:block-end_span-inline-end] [position-try-fallbacks:flip-block,flip-inline] open:translate-y-0 open:opacity-100 starting:open:translate-y-1.5 starting:open:opacity-0 motion-reduce:transition-none supports-[anchor-name:--a]:inset-auto supports-[anchor-name:--a]:m-0 supports-[anchor-name:--a]:mt-2.5 supports-[backdrop-filter:blur(1px)]:bg-tpop18-glass/55 supports-[backdrop-filter:blur(1px)]:backdrop-blur-[18px] supports-[backdrop-filter:blur(1px)]:backdrop-saturate-150">
<p class="mb-3 text-[10.5px] font-bold uppercase tracking-[0.2em] text-tpop18-mut">Track details</p>
<dl class="grid gap-2">
<div class="flex min-w-0 justify-between gap-3"><dt class="text-[13px] text-tpop18-mut">Length</dt><dd class="font-tpop18-mono text-[13px] font-semibold">6:41</dd></div>
<div class="flex min-w-0 justify-between gap-3"><dt class="text-[13px] text-tpop18-mut">Key</dt><dd class="text-[13px] font-semibold">D minor</dd></div>
<div class="flex min-w-0 justify-between gap-3"><dt class="text-[13px] text-tpop18-mut">Tempo</dt><dd class="font-tpop18-mono text-[13px] font-semibold">72 bpm</dd></div>
<div class="flex min-w-0 justify-between gap-3"><dt class="text-[13px] text-tpop18-mut">Mastered</dt><dd class="text-[13px] font-semibold">Alex Chen</dd></div>
</dl>
<p class="mt-3.5 border-t border-white/16 pt-3 text-xs text-tpop18-mut">Opaque fallback first, frost second.</p>
</div>
</section>@import "tailwindcss";
@theme {
--color-tpop18-night: #0f091c;
--color-tpop18-night: oklch(0.16 0.04 295);
--color-tpop18-violet: #4a237a;
--color-tpop18-violet: oklch(0.36 0.14 300);
--color-tpop18-teal: #005b6e;
--color-tpop18-teal: oklch(0.43 0.09 215);
--color-tpop18-rose: #9f2346;
--color-tpop18-rose: oklch(0.47 0.16 10);
--color-tpop18-glass: #221838;
--color-tpop18-glass: oklch(0.24 0.06 295);
--color-tpop18-ink: #f5f3ff;
--color-tpop18-ink: oklch(0.97 0.015 295);
--color-tpop18-mut: #ccc6e3;
--color-tpop18-mut: oklch(0.84 0.04 295);
--font-tpop18-sans: 'Bricolage Grotesque', system-ui, sans-serif;
--font-tpop18-mono: 'Geist Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles. */
.tpop-18 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tpop18-night: #0f091c;
--color-tpop18-night: oklch(0.16 0.04 295);
--color-tpop18-violet: #4a237a;
--color-tpop18-violet: oklch(0.36 0.14 300);
--color-tpop18-teal: #005b6e;
--color-tpop18-teal: oklch(0.43 0.09 215);
--color-tpop18-rose: #9f2346;
--color-tpop18-rose: oklch(0.47 0.16 10);
--color-tpop18-glass: #221838;
--color-tpop18-glass: oklch(0.24 0.06 295);
--color-tpop18-ink: #f5f3ff;
--color-tpop18-ink: oklch(0.97 0.015 295);
--color-tpop18-mut: #ccc6e3;
--color-tpop18-mut: oklch(0.84 0.04 295);
--font-tpop18-sans: 'Bricolage Grotesque', system-ui, sans-serif;
--font-tpop18-mono: 'Geist Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles. */
.tpop-18 {
width: 100%;
min-height: 100svh;
}Setup — do this once per project
Skip this if your project already runs Tailwind v4.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>Compiles in the browser — perfect for a CodePen or a quick test, not for production.
npm install tailwindcss @tailwindcss/vite
npm install tailwindcss @tailwindcss/vite// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})// vite.config.js ("type": "module" in package.json)
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})Any v4 setup works — Vite, PostCSS or the CLI. Nothing in this demo is bundler-specific.
@import "tailwindcss";
@theme {
--color-tpop18-night: #0f091c;
--color-tpop18-night: oklch(0.16 0.04 295);
--color-tpop18-violet: #4a237a;
--color-tpop18-violet: oklch(0.36 0.14 300);
--color-tpop18-teal: #005b6e;
--color-tpop18-teal: oklch(0.43 0.09 215);
--color-tpop18-rose: #9f2346;
--color-tpop18-rose: oklch(0.47 0.16 10);
--color-tpop18-glass: #221838;
--color-tpop18-glass: oklch(0.24 0.06 295);
--color-tpop18-ink: #f5f3ff;
--color-tpop18-ink: oklch(0.97 0.015 295);
--color-tpop18-mut: #ccc6e3;
--color-tpop18-mut: oklch(0.84 0.04 295);
--font-tpop18-sans: 'Bricolage Grotesque', system-ui, sans-serif;
--font-tpop18-mono: 'Geist Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles. */
.tpop-18 {
width: 100%;
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tpop18-night: #0f091c;
--color-tpop18-night: oklch(0.16 0.04 295);
--color-tpop18-violet: #4a237a;
--color-tpop18-violet: oklch(0.36 0.14 300);
--color-tpop18-teal: #005b6e;
--color-tpop18-teal: oklch(0.43 0.09 215);
--color-tpop18-rose: #9f2346;
--color-tpop18-rose: oklch(0.47 0.16 10);
--color-tpop18-glass: #221838;
--color-tpop18-glass: oklch(0.24 0.06 295);
--color-tpop18-ink: #f5f3ff;
--color-tpop18-ink: oklch(0.97 0.015 295);
--color-tpop18-mut: #ccc6e3;
--color-tpop18-mut: oklch(0.84 0.04 295);
--font-tpop18-sans: 'Bricolage Grotesque', system-ui, sans-serif;
--font-tpop18-mono: 'Geist Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles. */
.tpop-18 {
width: 100%;
min-height: 100svh;
}<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,400..800&family=Geist+Mono:wght@400..600&display=swap">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,400..800&family=Geist+Mono:wght@400..600&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- The nested
@supports (color-mix) { @supports (backdrop-filter) { … } }blocks became one variant: the opacity modifier/55already compiles tocolor-mix(), so only the backdrop-filter gate remains. - The four-layer background shorthand became one
bg-[radial-gradient(…),…]arbitrary value reading three theme tokens, overbg-tpop18-night. - UI upgrade from the CSS original: the now-playing screen gained conic-gradient artwork and a progress bar — real content for the glass to sit over — and the info button glows while its panel is open.
- UI upgrade: the panel lists tempo too, the title moved to Bricolage Grotesque at up to 52px, and muted copy rose from
#b8b0d8tooklch(0.84)so it clears 4.5:1 through the frost over the rose bloom.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Glassmorphism Popover
Source: https://codefronts.com/snippets/tailwind-css-popovers/tailwind-glassmorphism-popover/
A frosted panel over a rich aurora, with the opaque fallback as the base class and the frost layered on with supports-[backdrop-filter:blur(1px)]: — so an unsupporting engine shows a solid card, never text over raw colour. Because the panel lives in the top layer it has no transformed ancestor to become its backdrop root: the blur samples the real page.
## HTML
```html
<section class="tpop-18 group/root w-full min-h-svh bg-tpop18-night bg-[radial-gradient(46rem_30rem_at_12%_8%,var(--color-tpop18-violet),transparent_62%),radial-gradient(38rem_26rem_at_88%_22%,var(--color-tpop18-teal),transparent_60%),radial-gradient(34rem_28rem_at_62%_92%,var(--color-tpop18-rose),transparent_58%)] px-4.5 py-10 font-tpop18-sans text-tpop18-ink" aria-label="Glassmorphism popover demo">
<div class="grid min-h-[calc(100svh-80px)] max-w-full place-items-center">
<div class="w-full min-w-0 max-w-[28rem]">
<div aria-hidden="true" class="mb-6 size-28 rounded-3xl bg-[conic-gradient(from_210deg,var(--color-tpop18-rose),var(--color-tpop18-violet),var(--color-tpop18-teal),var(--color-tpop18-rose))] shadow-[0_24px_50px_-18px_oklch(0_0_0/0.7),inset_0_1px_0_oklch(1_0_0/0.3)]"></div>
<p class="mb-2.5 text-[10.5px] font-bold uppercase tracking-[0.24em] text-tpop18-mut">Now playing</p>
<h2 class="mb-1.5 text-[clamp(34px,8vw,52px)] font-bold leading-[0.98] tracking-[-0.035em]">Wickfield No. 5</h2>
<p class="mb-5 text-[15px] text-tpop18-mut">Marisa Ault · Slow Water · 2026</p>
<div class="mb-5 flex items-center gap-3 font-tpop18-mono text-[11.5px] text-tpop18-mut">
<span class="tabular-nums">2:14</span>
<span class="h-1 flex-auto overflow-hidden rounded-full bg-white/15"><span class="block h-full w-1/3 rounded-full bg-tpop18-ink"></span></span>
<span class="tabular-nums">6:41</span>
</div>
<button id="tpop-18-trigger" type="button" popovertarget="tpop-18-panel" aria-label="Track details" class="inline-flex size-11 cursor-pointer items-center justify-center rounded-full border border-white/30 bg-white/12 text-tpop18-ink transition-[background-color,box-shadow] duration-200 [anchor-name:--tpop18-a] hover:bg-white/20 focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-tpop18-ink group-has-[#tpop-18-panel:popover-open]/root:bg-white/25 group-has-[#tpop-18-panel:popover-open]/root:shadow-[0_0_24px_oklch(1_0_0/0.35)]">
<svg viewBox="0 0 22 22" width="19" height="19" fill="none" stroke="currentColor" stroke-width="1.7" aria-hidden="true"><circle cx="11" cy="11" r="8"/><path d="M11 10v5.4M11 7.2v.9"/></svg>
</button>
<p class="mt-5 max-w-[24rem] text-[13px] leading-relaxed text-tpop18-mut text-pretty">Open the panel: it blurs the top layer's view of this page, not a mocked-up copy of it.</p>
</div>
</div>
<div popover="auto" id="tpop-18-panel" role="group" aria-label="Track details" class="fixed m-auto w-[min(18rem,calc(100vw-28px))] rounded-3xl border border-white/30 bg-tpop18-glass p-4.5 text-tpop18-ink opacity-0 translate-y-1.5 shadow-[0_26px_60px_-28px_oklch(0_0_0/0.8),inset_0_1px_0_oklch(1_0_0/0.22)] transition-[opacity,translate,display,overlay] duration-200 ease-out transition-discrete [position-anchor:--tpop18-a] [position-area:block-end_span-inline-end] [position-try-fallbacks:flip-block,flip-inline] open:translate-y-0 open:opacity-100 starting:open:translate-y-1.5 starting:open:opacity-0 motion-reduce:transition-none supports-[anchor-name:--a]:inset-auto supports-[anchor-name:--a]:m-0 supports-[anchor-name:--a]:mt-2.5 supports-[backdrop-filter:blur(1px)]:bg-tpop18-glass/55 supports-[backdrop-filter:blur(1px)]:backdrop-blur-[18px] supports-[backdrop-filter:blur(1px)]:backdrop-saturate-150">
<p class="mb-3 text-[10.5px] font-bold uppercase tracking-[0.2em] text-tpop18-mut">Track details</p>
<dl class="grid gap-2">
<div class="flex min-w-0 justify-between gap-3"><dt class="text-[13px] text-tpop18-mut">Length</dt><dd class="font-tpop18-mono text-[13px] font-semibold">6:41</dd></div>
<div class="flex min-w-0 justify-between gap-3"><dt class="text-[13px] text-tpop18-mut">Key</dt><dd class="text-[13px] font-semibold">D minor</dd></div>
<div class="flex min-w-0 justify-between gap-3"><dt class="text-[13px] text-tpop18-mut">Tempo</dt><dd class="font-tpop18-mono text-[13px] font-semibold">72 bpm</dd></div>
<div class="flex min-w-0 justify-between gap-3"><dt class="text-[13px] text-tpop18-mut">Mastered</dt><dd class="text-[13px] font-semibold">Alex Chen</dd></div>
</dl>
<p class="mt-3.5 border-t border-white/16 pt-3 text-xs text-tpop18-mut">Opaque fallback first, frost second.</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tpop18-night: #0f091c;
--color-tpop18-night: oklch(0.16 0.04 295);
--color-tpop18-violet: #4a237a;
--color-tpop18-violet: oklch(0.36 0.14 300);
--color-tpop18-teal: #005b6e;
--color-tpop18-teal: oklch(0.43 0.09 215);
--color-tpop18-rose: #9f2346;
--color-tpop18-rose: oklch(0.47 0.16 10);
--color-tpop18-glass: #221838;
--color-tpop18-glass: oklch(0.24 0.06 295);
--color-tpop18-ink: #f5f3ff;
--color-tpop18-ink: oklch(0.97 0.015 295);
--color-tpop18-mut: #ccc6e3;
--color-tpop18-mut: oklch(0.84 0.04 295);
--font-tpop18-sans: 'Bricolage Grotesque', system-ui, sans-serif;
--font-tpop18-mono: 'Geist Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles. */
.tpop-18 {
width: 100%;
min-height: 100svh;
}
```Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Tailwind Glassmorphism Popover
Source: https://codefronts.com/snippets/tailwind-css-popovers/tailwind-glassmorphism-popover/
A frosted panel over a rich aurora, with the opaque fallback as the base class and the frost layered on with supports-[backdrop-filter:blur(1px)]: — so an unsupporting engine shows a solid card, never text over raw colour. Because the panel lives in the top layer it has no transformed ancestor to become its backdrop root: the blur samples the real page.
## HTML
```html
<section class="tpop-18 group/root w-full min-h-svh bg-tpop18-night bg-[radial-gradient(46rem_30rem_at_12%_8%,var(--color-tpop18-violet),transparent_62%),radial-gradient(38rem_26rem_at_88%_22%,var(--color-tpop18-teal),transparent_60%),radial-gradient(34rem_28rem_at_62%_92%,var(--color-tpop18-rose),transparent_58%)] px-4.5 py-10 font-tpop18-sans text-tpop18-ink" aria-label="Glassmorphism popover demo">
<div class="grid min-h-[calc(100svh-80px)] max-w-full place-items-center">
<div class="w-full min-w-0 max-w-[28rem]">
<div aria-hidden="true" class="mb-6 size-28 rounded-3xl bg-[conic-gradient(from_210deg,var(--color-tpop18-rose),var(--color-tpop18-violet),var(--color-tpop18-teal),var(--color-tpop18-rose))] shadow-[0_24px_50px_-18px_oklch(0_0_0/0.7),inset_0_1px_0_oklch(1_0_0/0.3)]"></div>
<p class="mb-2.5 text-[10.5px] font-bold uppercase tracking-[0.24em] text-tpop18-mut">Now playing</p>
<h2 class="mb-1.5 text-[clamp(34px,8vw,52px)] font-bold leading-[0.98] tracking-[-0.035em]">Wickfield No. 5</h2>
<p class="mb-5 text-[15px] text-tpop18-mut">Marisa Ault · Slow Water · 2026</p>
<div class="mb-5 flex items-center gap-3 font-tpop18-mono text-[11.5px] text-tpop18-mut">
<span class="tabular-nums">2:14</span>
<span class="h-1 flex-auto overflow-hidden rounded-full bg-white/15"><span class="block h-full w-1/3 rounded-full bg-tpop18-ink"></span></span>
<span class="tabular-nums">6:41</span>
</div>
<button id="tpop-18-trigger" type="button" popovertarget="tpop-18-panel" aria-label="Track details" class="inline-flex size-11 cursor-pointer items-center justify-center rounded-full border border-white/30 bg-white/12 text-tpop18-ink transition-[background-color,box-shadow] duration-200 [anchor-name:--tpop18-a] hover:bg-white/20 focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-tpop18-ink group-has-[#tpop-18-panel:popover-open]/root:bg-white/25 group-has-[#tpop-18-panel:popover-open]/root:shadow-[0_0_24px_oklch(1_0_0/0.35)]">
<svg viewBox="0 0 22 22" width="19" height="19" fill="none" stroke="currentColor" stroke-width="1.7" aria-hidden="true"><circle cx="11" cy="11" r="8"/><path d="M11 10v5.4M11 7.2v.9"/></svg>
</button>
<p class="mt-5 max-w-[24rem] text-[13px] leading-relaxed text-tpop18-mut text-pretty">Open the panel: it blurs the top layer's view of this page, not a mocked-up copy of it.</p>
</div>
</div>
<div popover="auto" id="tpop-18-panel" role="group" aria-label="Track details" class="fixed m-auto w-[min(18rem,calc(100vw-28px))] rounded-3xl border border-white/30 bg-tpop18-glass p-4.5 text-tpop18-ink opacity-0 translate-y-1.5 shadow-[0_26px_60px_-28px_oklch(0_0_0/0.8),inset_0_1px_0_oklch(1_0_0/0.22)] transition-[opacity,translate,display,overlay] duration-200 ease-out transition-discrete [position-anchor:--tpop18-a] [position-area:block-end_span-inline-end] [position-try-fallbacks:flip-block,flip-inline] open:translate-y-0 open:opacity-100 starting:open:translate-y-1.5 starting:open:opacity-0 motion-reduce:transition-none supports-[anchor-name:--a]:inset-auto supports-[anchor-name:--a]:m-0 supports-[anchor-name:--a]:mt-2.5 supports-[backdrop-filter:blur(1px)]:bg-tpop18-glass/55 supports-[backdrop-filter:blur(1px)]:backdrop-blur-[18px] supports-[backdrop-filter:blur(1px)]:backdrop-saturate-150">
<p class="mb-3 text-[10.5px] font-bold uppercase tracking-[0.2em] text-tpop18-mut">Track details</p>
<dl class="grid gap-2">
<div class="flex min-w-0 justify-between gap-3"><dt class="text-[13px] text-tpop18-mut">Length</dt><dd class="font-tpop18-mono text-[13px] font-semibold">6:41</dd></div>
<div class="flex min-w-0 justify-between gap-3"><dt class="text-[13px] text-tpop18-mut">Key</dt><dd class="text-[13px] font-semibold">D minor</dd></div>
<div class="flex min-w-0 justify-between gap-3"><dt class="text-[13px] text-tpop18-mut">Tempo</dt><dd class="font-tpop18-mono text-[13px] font-semibold">72 bpm</dd></div>
<div class="flex min-w-0 justify-between gap-3"><dt class="text-[13px] text-tpop18-mut">Mastered</dt><dd class="text-[13px] font-semibold">Alex Chen</dd></div>
</dl>
<p class="mt-3.5 border-t border-white/16 pt-3 text-xs text-tpop18-mut">Opaque fallback first, frost second.</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tpop18-night: #0f091c;
--color-tpop18-night: oklch(0.16 0.04 295);
--color-tpop18-violet: #4a237a;
--color-tpop18-violet: oklch(0.36 0.14 300);
--color-tpop18-teal: #005b6e;
--color-tpop18-teal: oklch(0.43 0.09 215);
--color-tpop18-rose: #9f2346;
--color-tpop18-rose: oklch(0.47 0.16 10);
--color-tpop18-glass: #221838;
--color-tpop18-glass: oklch(0.24 0.06 295);
--color-tpop18-ink: #f5f3ff;
--color-tpop18-ink: oklch(0.97 0.015 295);
--color-tpop18-mut: #ccc6e3;
--color-tpop18-mut: oklch(0.84 0.04 295);
--font-tpop18-sans: 'Bricolage Grotesque', system-ui, sans-serif;
--font-tpop18-mono: 'Geist Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
stage is sized before the browser build compiles. */
.tpop-18 {
width: 100%;
min-height: 100svh;
}
```How this works
Glass is two declarations and one guarantee.
class="bg-tpop18-glass
supports-[backdrop-filter:blur(1px)]:bg-tpop18-glass/55
supports-[backdrop-filter:blur(1px)]:backdrop-blur-[18px]
supports-[backdrop-filter:blur(1px)]:backdrop-saturate-150"Blur without saturate drains the colour and the panel reads dirty grey; saturate brings it back. The guarantee is legibility: the unprefixed background is fully opaque, and only engines that can blur get the translucent one.
The top layer changes what gets sampled. backdrop-filter blurs whatever is painted behind the element; an ancestor with transform, filter or will-change would become the backdrop root and the blur would sample only that subtree. A popover in the top layer has no such ancestor — quietly one of the best reasons to build glass on popover.
Test contrast against the lightest region. The 55% tint keeps body text above 4.5:1 even over the pink bloom.
Make it yours
- More frost, less tint:
bg-tpop18-glass/40withbackdrop-blur-2xl. - Light glass: swap the token to white and use
bg-white/60with dark ink. - Sharper utility card:
rounded-mdinstead ofrounded-3xl.
Gotchas — read before shipping
- Shipping translucency without an opaque base leaves text over raw colour where
backdrop-filteris missing. - A transformed ancestor becomes the backdrop root — a bug that disappears in the top layer.
- Glass over bright imagery routinely fails 4.5:1; check the lightest region, not the average.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 125+ | 26+ | 131+ | 125+ |
backdrop-filter is Chrome 76 / Safari 18 unprefixed / Firefox 103; the floor comes from anchoring the panel. Without backdrop-filter the opaque card is a complete design.