Pure TailwindMIT licensed

Tailwind Glassmorphism Overlay on Image Hover

A frosted panel parked below the frame that rises into the card on hover. Two backdrop utilities do the glass (backdrop-blur-xl backdrop-saturate-150), one arbitrary translate parks it, and the resting title fades out as the panel arrives — so the card never shows two competing labels mid-transition.

Live Demo
Plain CSSTailwind v4
Try it

Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time

Untitled UI React · Affiliate link

Get Untitled UI Pro

The code

<section class="tih-09 w-full min-h-svh grid place-items-center bg-tih09-bg font-tih09-sans px-6 py-10" aria-label="Glassmorphism overlay on image hover demo">
  <div class="grid w-full max-w-195 gap-4 grid-cols-1 sm:grid-cols-3">
    <article class="group relative overflow-hidden rounded-2xl aspect-[3/4]">
      <div class="absolute inset-0 grid place-items-center bg-[image:url('https://picsum.photos/seed/tih09-spring/600/800'),linear-gradient(145deg,oklch(0.16_0.07_310),oklch(0.28_0.13_290),oklch(0.4_0.19_295),oklch(0.55_0.24_295))] bg-cover bg-center bg-no-repeat transition-transform duration-450 ease-tih09 group-hover:scale-108 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
      </div>
      <div class="absolute inset-x-0 bottom-0 p-4 bg-linear-[to_top,oklch(0_0_0/0.7),transparent]">
        <p class="text-[13px] font-semibold text-tih09-text transition-opacity duration-450 ease-tih09 group-hover:opacity-0 motion-reduce:transition-none motion-reduce:opacity-0">Spring Collection</p>
      </div>
      <div class="absolute inset-x-3 bottom-3 p-4 rounded-xl bg-[oklch(1_0_0/0.08)] backdrop-blur-xl backdrop-saturate-150 border border-[oklch(1_0_0/0.15)] opacity-0 [translate:0_calc(100%+16px)] transition-[translate,opacity] duration-450 ease-tih09 group-hover:translate-y-0 group-hover:opacity-100 focus-within:translate-y-0 focus-within:opacity-100 motion-reduce:transition-none motion-reduce:translate-y-0 motion-reduce:opacity-100">
        <p class="mb-1.5 text-[9px] font-bold tracking-[0.12em] uppercase text-tih09-acc">Collection</p>
        <h3 class="mb-1 text-sm font-bold text-tih09-text">Spring Bloom 2026</h3>
        <p class="text-[11px] leading-[1.5] text-[oklch(0.96_0.005_250/0.7)]">Ethereal violet pieces inspired by cherry blossom season</p>
        <div class="flex items-center justify-between mt-2.5">
          <span class="text-[10px] text-tih09-muted">24 pieces</span>
          <a href="#spring-bloom" class="text-[10px] font-bold tracking-[0.06em] text-tih09-acc no-underline rounded focus-visible:outline-2 focus-visible:outline-tih09-acc focus-visible:outline-offset-3">Explore &rarr;</a>
        </div>
      </div>
    </article>
    <article class="group relative overflow-hidden rounded-2xl aspect-[3/4]">
      <div class="absolute inset-0 grid place-items-center bg-[image:url('https://picsum.photos/seed/tih09-forest/600/800'),linear-gradient(145deg,oklch(0.2_0.05_165),oklch(0.35_0.09_163),oklch(0.55_0.13_163),oklch(0.8_0.14_163))] bg-cover bg-center bg-no-repeat transition-transform duration-450 ease-tih09 group-hover:scale-108 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
      </div>
      <div class="absolute inset-x-0 bottom-0 p-4 bg-linear-[to_top,oklch(0_0_0/0.7),transparent]">
        <p class="text-[13px] font-semibold text-tih09-text transition-opacity duration-450 ease-tih09 group-hover:opacity-0 motion-reduce:transition-none motion-reduce:opacity-0">Earth Tones</p>
      </div>
      <div class="absolute inset-x-3 bottom-3 p-4 rounded-xl bg-[oklch(1_0_0/0.08)] backdrop-blur-xl backdrop-saturate-150 border border-[oklch(1_0_0/0.15)] opacity-0 [translate:0_calc(100%+16px)] transition-[translate,opacity] duration-450 ease-tih09 group-hover:translate-y-0 group-hover:opacity-100 focus-within:translate-y-0 focus-within:opacity-100 motion-reduce:transition-none motion-reduce:translate-y-0 motion-reduce:opacity-100">
        <p class="mb-1.5 text-[9px] font-bold tracking-[0.12em] uppercase text-tih09-acc">Sustainable</p>
        <h3 class="mb-1 text-sm font-bold text-tih09-text">Forest Origins</h3>
        <p class="text-[11px] leading-[1.5] text-[oklch(0.96_0.005_250/0.7)]">Organic cotton pieces dyed with natural plant extracts</p>
        <div class="flex items-center justify-between mt-2.5">
          <span class="text-[10px] text-tih09-muted">18 pieces</span>
          <a href="#forest-origins" class="text-[10px] font-bold tracking-[0.06em] text-tih09-acc no-underline rounded focus-visible:outline-2 focus-visible:outline-tih09-acc focus-visible:outline-offset-3">Explore &rarr;</a>
        </div>
      </div>
    </article>
    <article class="group relative overflow-hidden rounded-2xl aspect-[3/4]">
      <div class="absolute inset-0 grid place-items-center bg-[image:url('https://picsum.photos/seed/tih09-azure/600/800'),linear-gradient(145deg,oklch(0.17_0.08_265),oklch(0.32_0.14_262),oklch(0.45_0.2_260),oklch(0.72_0.14_255))] bg-cover bg-center bg-no-repeat transition-transform duration-450 ease-tih09 group-hover:scale-108 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
      </div>
      <div class="absolute inset-x-0 bottom-0 p-4 bg-linear-[to_top,oklch(0_0_0/0.7),transparent]">
        <p class="text-[13px] font-semibold text-tih09-text transition-opacity duration-450 ease-tih09 group-hover:opacity-0 motion-reduce:transition-none motion-reduce:opacity-0">Azure Line</p>
      </div>
      <div class="absolute inset-x-3 bottom-3 p-4 rounded-xl bg-[oklch(1_0_0/0.08)] backdrop-blur-xl backdrop-saturate-150 border border-[oklch(1_0_0/0.15)] opacity-0 [translate:0_calc(100%+16px)] transition-[translate,opacity] duration-450 ease-tih09 group-hover:translate-y-0 group-hover:opacity-100 focus-within:translate-y-0 focus-within:opacity-100 motion-reduce:transition-none motion-reduce:translate-y-0 motion-reduce:opacity-100">
        <p class="mb-1.5 text-[9px] font-bold tracking-[0.12em] uppercase text-tih09-acc">Limited</p>
        <h3 class="mb-1 text-sm font-bold text-tih09-text">Azure Coast</h3>
        <p class="text-[11px] leading-[1.5] text-[oklch(0.96_0.005_250/0.7)]">Mediterranean-inspired linen pieces for summer living</p>
        <div class="flex items-center justify-between mt-2.5">
          <span class="text-[10px] text-tih09-muted">12 pieces</span>
          <a href="#azure-coast" class="text-[10px] font-bold tracking-[0.06em] text-tih09-acc no-underline rounded focus-visible:outline-2 focus-visible:outline-tih09-acc focus-visible:outline-offset-3">Explore &rarr;</a>
        </div>
      </div>
    </article>
  </div>
</section>
@import "tailwindcss";

@theme {
  --color-tih09-bg: #060611;
  --color-tih09-bg: oklch(0.11 0.015 285);
  --color-tih09-text: #f1f5f9;
  --color-tih09-text: oklch(0.96 0.005 250);
  --color-tih09-muted: #94a3b8;
  --color-tih09-muted: oklch(0.7 0.03 250);
  --color-tih09-acc: #8b5cf6;
  --color-tih09-acc: oklch(0.62 0.21 295);
  --font-tih09-sans: 'Space Grotesk', system-ui, sans-serif;
  --ease-tih09: cubic-bezier(0.16, 1, 0.3, 1);
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
   w-full min-h-svh, so the stage is correctly sized before the browser build compiles. */

.tih-09 {
  width: 100%;
  min-height: 100svh;
}

.tih-09 ::selection {
  background: oklch(0.62 0.21 295 / 0.8);
  color: #fff;
}

Setup — do this once per project

Skip this if your project already runs Tailwind v4.

1Load Tailwind
<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.

2Add the stylesheetRequiredthe @theme block is what makes the custom utilities exist
@import "tailwindcss";

@theme {
  --color-tih09-bg: #060611;
  --color-tih09-bg: oklch(0.11 0.015 285);
  --color-tih09-text: #f1f5f9;
  --color-tih09-text: oklch(0.96 0.005 250);
  --color-tih09-muted: #94a3b8;
  --color-tih09-muted: oklch(0.7 0.03 250);
  --color-tih09-acc: #8b5cf6;
  --color-tih09-acc: oklch(0.62 0.21 295);
  --font-tih09-sans: 'Space Grotesk', system-ui, sans-serif;
  --ease-tih09: cubic-bezier(0.16, 1, 0.3, 1);
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
   w-full min-h-svh, so the stage is correctly sized before the browser build compiles. */

.tih-09 {
  width: 100%;
  min-height: 100svh;
}

.tih-09 ::selection {
  background: oklch(0.62 0.21 295 / 0.8);
  color: #fff;
}
3Fonts used by this demooptional — skip if you have your own type stack
<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=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap">

What changed in the port

Which parts became utilities, which stayed CSS, and why.

  • The glass recipe — blur plus saturate plus the -webkit- twin — becomes backdrop-blur-xl backdrop-saturate-150. Tailwind writes the prefix.
  • translateY(calc(100% + 16px)) becomes [translate:0_calc(100%+16px)], and the override is a plain group-hover:translate-y-0 rather than a second full transform.
  • Two hover rules (panel in, resting title out) become two group-hover: utilities on the two elements, so the handover is visible as a pair rather than inferred from rule order.
  • focus-within: on the panel is added by the port: the panel contains a link, and a parked panel with a focusable child is a focus-order bug in the CSS original.
  • The translucent fill stays a bg- utility rather than being folded into the filter, which is what keeps the Firefox-below-103 fallback legible.
  • motion-reduce: promotes the panel to always-open and drops the resting strip — the card reads as a static caption card, which is the correct no-motion form.
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
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 Overlay on Image Hover
Source: https://codefronts.com/motion/tailwind-css-image-hover-effects/tailwind-glassmorphism-overlay-on-image-hover/

A frosted panel parked below the frame that rises into the card on hover. Two backdrop utilities do the glass (backdrop-blur-xl backdrop-saturate-150), one arbitrary translate parks it, and the resting title fades out as the panel arrives &mdash; so the card never shows two competing labels mid-transition.
## HTML
```html
<section class="tih-09 w-full min-h-svh grid place-items-center bg-tih09-bg font-tih09-sans px-6 py-10" aria-label="Glassmorphism overlay on image hover demo">
  <div class="grid w-full max-w-195 gap-4 grid-cols-1 sm:grid-cols-3">
    <article class="group relative overflow-hidden rounded-2xl aspect-[3/4]">
      <div class="absolute inset-0 grid place-items-center bg-[image:url('https://picsum.photos/seed/tih09-spring/600/800'),linear-gradient(145deg,oklch(0.16_0.07_310),oklch(0.28_0.13_290),oklch(0.4_0.19_295),oklch(0.55_0.24_295))] bg-cover bg-center bg-no-repeat transition-transform duration-450 ease-tih09 group-hover:scale-108 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
      </div>
      <div class="absolute inset-x-0 bottom-0 p-4 bg-linear-[to_top,oklch(0_0_0/0.7),transparent]">
        <p class="text-[13px] font-semibold text-tih09-text transition-opacity duration-450 ease-tih09 group-hover:opacity-0 motion-reduce:transition-none motion-reduce:opacity-0">Spring Collection</p>
      </div>
      <div class="absolute inset-x-3 bottom-3 p-4 rounded-xl bg-[oklch(1_0_0/0.08)] backdrop-blur-xl backdrop-saturate-150 border border-[oklch(1_0_0/0.15)] opacity-0 [translate:0_calc(100%+16px)] transition-[translate,opacity] duration-450 ease-tih09 group-hover:translate-y-0 group-hover:opacity-100 focus-within:translate-y-0 focus-within:opacity-100 motion-reduce:transition-none motion-reduce:translate-y-0 motion-reduce:opacity-100">
        <p class="mb-1.5 text-[9px] font-bold tracking-[0.12em] uppercase text-tih09-acc">Collection</p>
        <h3 class="mb-1 text-sm font-bold text-tih09-text">Spring Bloom 2026</h3>
        <p class="text-[11px] leading-[1.5] text-[oklch(0.96_0.005_250/0.7)]">Ethereal violet pieces inspired by cherry blossom season</p>
        <div class="flex items-center justify-between mt-2.5">
          <span class="text-[10px] text-tih09-muted">24 pieces</span>
          <a href="#spring-bloom" class="text-[10px] font-bold tracking-[0.06em] text-tih09-acc no-underline rounded focus-visible:outline-2 focus-visible:outline-tih09-acc focus-visible:outline-offset-3">Explore &rarr;</a>
        </div>
      </div>
    </article>
    <article class="group relative overflow-hidden rounded-2xl aspect-[3/4]">
      <div class="absolute inset-0 grid place-items-center bg-[image:url('https://picsum.photos/seed/tih09-forest/600/800'),linear-gradient(145deg,oklch(0.2_0.05_165),oklch(0.35_0.09_163),oklch(0.55_0.13_163),oklch(0.8_0.14_163))] bg-cover bg-center bg-no-repeat transition-transform duration-450 ease-tih09 group-hover:scale-108 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
      </div>
      <div class="absolute inset-x-0 bottom-0 p-4 bg-linear-[to_top,oklch(0_0_0/0.7),transparent]">
        <p class="text-[13px] font-semibold text-tih09-text transition-opacity duration-450 ease-tih09 group-hover:opacity-0 motion-reduce:transition-none motion-reduce:opacity-0">Earth Tones</p>
      </div>
      <div class="absolute inset-x-3 bottom-3 p-4 rounded-xl bg-[oklch(1_0_0/0.08)] backdrop-blur-xl backdrop-saturate-150 border border-[oklch(1_0_0/0.15)] opacity-0 [translate:0_calc(100%+16px)] transition-[translate,opacity] duration-450 ease-tih09 group-hover:translate-y-0 group-hover:opacity-100 focus-within:translate-y-0 focus-within:opacity-100 motion-reduce:transition-none motion-reduce:translate-y-0 motion-reduce:opacity-100">
        <p class="mb-1.5 text-[9px] font-bold tracking-[0.12em] uppercase text-tih09-acc">Sustainable</p>
        <h3 class="mb-1 text-sm font-bold text-tih09-text">Forest Origins</h3>
        <p class="text-[11px] leading-[1.5] text-[oklch(0.96_0.005_250/0.7)]">Organic cotton pieces dyed with natural plant extracts</p>
        <div class="flex items-center justify-between mt-2.5">
          <span class="text-[10px] text-tih09-muted">18 pieces</span>
          <a href="#forest-origins" class="text-[10px] font-bold tracking-[0.06em] text-tih09-acc no-underline rounded focus-visible:outline-2 focus-visible:outline-tih09-acc focus-visible:outline-offset-3">Explore &rarr;</a>
        </div>
      </div>
    </article>
    <article class="group relative overflow-hidden rounded-2xl aspect-[3/4]">
      <div class="absolute inset-0 grid place-items-center bg-[image:url('https://picsum.photos/seed/tih09-azure/600/800'),linear-gradient(145deg,oklch(0.17_0.08_265),oklch(0.32_0.14_262),oklch(0.45_0.2_260),oklch(0.72_0.14_255))] bg-cover bg-center bg-no-repeat transition-transform duration-450 ease-tih09 group-hover:scale-108 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
      </div>
      <div class="absolute inset-x-0 bottom-0 p-4 bg-linear-[to_top,oklch(0_0_0/0.7),transparent]">
        <p class="text-[13px] font-semibold text-tih09-text transition-opacity duration-450 ease-tih09 group-hover:opacity-0 motion-reduce:transition-none motion-reduce:opacity-0">Azure Line</p>
      </div>
      <div class="absolute inset-x-3 bottom-3 p-4 rounded-xl bg-[oklch(1_0_0/0.08)] backdrop-blur-xl backdrop-saturate-150 border border-[oklch(1_0_0/0.15)] opacity-0 [translate:0_calc(100%+16px)] transition-[translate,opacity] duration-450 ease-tih09 group-hover:translate-y-0 group-hover:opacity-100 focus-within:translate-y-0 focus-within:opacity-100 motion-reduce:transition-none motion-reduce:translate-y-0 motion-reduce:opacity-100">
        <p class="mb-1.5 text-[9px] font-bold tracking-[0.12em] uppercase text-tih09-acc">Limited</p>
        <h3 class="mb-1 text-sm font-bold text-tih09-text">Azure Coast</h3>
        <p class="text-[11px] leading-[1.5] text-[oklch(0.96_0.005_250/0.7)]">Mediterranean-inspired linen pieces for summer living</p>
        <div class="flex items-center justify-between mt-2.5">
          <span class="text-[10px] text-tih09-muted">12 pieces</span>
          <a href="#azure-coast" class="text-[10px] font-bold tracking-[0.06em] text-tih09-acc no-underline rounded focus-visible:outline-2 focus-visible:outline-tih09-acc focus-visible:outline-offset-3">Explore &rarr;</a>
        </div>
      </div>
    </article>
  </div>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-tih09-bg: #060611;
  --color-tih09-bg: oklch(0.11 0.015 285);
  --color-tih09-text: #f1f5f9;
  --color-tih09-text: oklch(0.96 0.005 250);
  --color-tih09-muted: #94a3b8;
  --color-tih09-muted: oklch(0.7 0.03 250);
  --color-tih09-acc: #8b5cf6;
  --color-tih09-acc: oklch(0.62 0.21 295);
  --font-tih09-sans: 'Space Grotesk', system-ui, sans-serif;
  --ease-tih09: cubic-bezier(0.16, 1, 0.3, 1);
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
   w-full min-h-svh, so the stage is correctly sized before the browser build compiles. */

.tih-09 {
  width: 100%;
  min-height: 100svh;
}

.tih-09 ::selection {
  background: oklch(0.62 0.21 295 / 0.8);
  color: #fff;
}
```

How this works

Glass is two utilities. backdrop-blur-xl plus backdrop-saturate-150 compose into one backdrop-filter, with the -webkit- twin emitted automatically. The rim light and the translucent fill stay separate border and bg- utilities, which is right — they are surface, not filter.

Parked, not hidden.

class="absolute inset-x-3 bottom-3 opacity-0
   [translate:0_calc(100%+16px)]
   transition-[translate,opacity] duration-450 ease-tih09
   group-hover:translate-y-0 group-hover:opacity-100"

The +16px covers the panel's own bottom-3 inset so it fully clears the frame; a plain translate-y-full would leave a 12px sliver visible.

Two labels, one at a time. The resting gradient strip carries the collection name so the card is never anonymous; its group-hover:opacity-0 retires it exactly as the glass rises.

Make it yours

  • Frost: backdrop-blur-md for a haze, backdrop-blur-3xl for near-opaque.
  • Brand glass: bg-[oklch(0.62_0.21_295/0.1)] tints the panel without losing translucency.
  • Side drawer: [translate:calc(100%+16px)_0] with inset-y-3 right-3.
  • Give the panel a floor with min-h-28 so short copy does not produce a thin sliver.
  • Retheme through --color-tih09-acc — the eyebrow, the CTA and the focus ring read it.

Gotchas — read before shipping

  • backdrop-filter only blurs what is painted behind the element in the same stacking context — the panel must come after the artwork in the DOM.
  • The card's overflow-hidden clips the panel as it travels, which is what you want here; if you need the panel to overhang, move the clip to an outer wrapper.
  • Firefox below 103 renders the panel unblurred. The 8% white fill keeps it legible, which is why the fill is not left to the filter.
  • translate-y-full is not equivalent to the calc: it ignores the panel's inset and leaves an edge showing.
  • The panel contains a CTA, so it needs focus-within:translate-y-0 — otherwise keyboard focus lands on something parked off-frame.
  • The browser CDN build compiles in the page and is for prototyping only. Ship the CLI or a plugin build.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

backdrop-filter is Chrome 76+, Safari 9+ prefixed, Firefox 103+; older Firefox shows an unblurred but legible translucent panel.

Techniques used in this demo

Arbitraryneeds bracket syntax

Search CodeFronts

Loading…