Pure TailwindMIT licensed

Tailwind Shining Light Glare Image Hover

A bright band swept across the artwork by a single pseudo-element — and in utilities the entire sweep is an after: chain on the frame: after:[translate:-200%] group-hover:after:[translate:300%]. No extra markup, no separate rule block, and the two ends of the travel sit next to each other.

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-13 w-full min-h-svh grid place-items-center bg-tih13-bg font-tih13-sans px-6 py-10" aria-label="Shining light glare 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-[14px] border border-[oklch(1_0_0/0.06)] transition-[border-color,box-shadow] duration-600 ease-tih13 hover:border-[oklch(0.84_0.16_85/0.3)] hover:shadow-[0_8px_40px_oklch(0.84_0.16_85/0.12)] motion-reduce:transition-none">
      <div class="relative aspect-[4/3] grid place-items-center overflow-hidden bg-[image:url('https://picsum.photos/seed/tih13-gold/800/600'),linear-gradient(135deg,oklch(0.18_0.03_60),oklch(0.32_0.08_55),oklch(0.55_0.13_65),oklch(0.84_0.16_85))] bg-cover bg-center bg-no-repeat after:content-[''] after:absolute after:-inset-1/2 after:w-2/5 after:h-[200%] after:bg-linear-[105deg,transparent_40%,oklch(1_0_0/0.08)_45%,oklch(1_0_0/0.22)_50%,oklch(1_0_0/0.08)_55%,transparent_60%] after:skew-x-[-10deg] after:[translate:-200%] after:transition-[translate] after:duration-600 after:ease-tih13 group-hover:after:[translate:300%] motion-reduce:after:hidden">
      </div>
      <div class="px-4 py-3.5 bg-[oklch(0_0_0/0.4)]">
        <p class="mb-1.25 text-[9px] font-bold tracking-[0.12em] uppercase text-tih13-acc">Premium</p>
        <h3 class="text-sm font-bold text-tih13-text">Gold Tier Membership</h3>
        <p class="mt-0.5 text-[11px] tracking-[-1px] text-tih13-acc" aria-label="Rated 5 out of 5">&#9733;&#9733;&#9733;&#9733;&#9733;</p>
        <p class="mt-1.5 text-base font-extrabold text-tih13-acc tabular-nums">$49 / mo</p>
      </div>
    </article>
    <article class="group relative overflow-hidden rounded-[14px] border border-[oklch(1_0_0/0.06)] transition-[border-color,box-shadow] duration-600 ease-tih13 hover:border-[oklch(0.84_0.16_85/0.3)] hover:shadow-[0_8px_40px_oklch(0.84_0.16_85/0.12)] motion-reduce:transition-none">
      <div class="relative aspect-[4/3] grid place-items-center overflow-hidden bg-[image:url('https://picsum.photos/seed/tih13-platinum/800/600'),linear-gradient(135deg,oklch(0.15_0_0),oklch(0.25_0_0),oklch(0.4_0_0),oklch(0.72_0_0))] bg-cover bg-center bg-no-repeat after:content-[''] after:absolute after:-inset-1/2 after:w-2/5 after:h-[200%] after:bg-linear-[105deg,transparent_40%,oklch(1_0_0/0.08)_45%,oklch(1_0_0/0.22)_50%,oklch(1_0_0/0.08)_55%,transparent_60%] after:skew-x-[-10deg] after:[translate:-200%] after:transition-[translate] after:duration-600 after:ease-tih13 group-hover:after:[translate:300%] motion-reduce:after:hidden">
      </div>
      <div class="px-4 py-3.5 bg-[oklch(0_0_0/0.4)]">
        <p class="mb-1.25 text-[9px] font-bold tracking-[0.12em] uppercase text-tih13-acc">Exclusive</p>
        <h3 class="text-sm font-bold text-tih13-text">Platinum Credit Card</h3>
        <p class="mt-0.5 text-[11px] tracking-[-1px] text-tih13-acc" aria-label="Rated 5 out of 5">&#9733;&#9733;&#9733;&#9733;&#9733;</p>
        <p class="mt-1.5 text-base font-extrabold text-tih13-acc tabular-nums">0% APR 18mo</p>
      </div>
    </article>
    <article class="group relative overflow-hidden rounded-[14px] border border-[oklch(1_0_0/0.06)] transition-[border-color,box-shadow] duration-600 ease-tih13 hover:border-[oklch(0.84_0.16_85/0.3)] hover:shadow-[0_8px_40px_oklch(0.84_0.16_85/0.12)] motion-reduce:transition-none">
      <div class="relative aspect-[4/3] grid place-items-center overflow-hidden bg-[image:url('https://picsum.photos/seed/tih13-diamond/800/600'),linear-gradient(135deg,oklch(0.17_0.07_310),oklch(0.35_0.18_295),oklch(0.55_0.24_295),oklch(0.83_0.1_295))] bg-cover bg-center bg-no-repeat after:content-[''] after:absolute after:-inset-1/2 after:w-2/5 after:h-[200%] after:bg-linear-[105deg,transparent_40%,oklch(1_0_0/0.08)_45%,oklch(1_0_0/0.22)_50%,oklch(1_0_0/0.08)_55%,transparent_60%] after:skew-x-[-10deg] after:[translate:-200%] after:transition-[translate] after:duration-600 after:ease-tih13 group-hover:after:[translate:300%] motion-reduce:after:hidden">
      </div>
      <div class="px-4 py-3.5 bg-[oklch(0_0_0/0.4)]">
        <p class="mb-1.25 text-[9px] font-bold tracking-[0.12em] uppercase text-tih13-acc">Diamond</p>
        <h3 class="text-sm font-bold text-tih13-text">Crystal Pro Bundle</h3>
        <p class="mt-0.5 text-[11px] tracking-[-1px] text-tih13-acc" aria-label="Rated 5 out of 5">&#9733;&#9733;&#9733;&#9733;&#9733;</p>
        <p class="mt-1.5 text-base font-extrabold text-tih13-acc tabular-nums">$299 / yr</p>
      </div>
    </article>
  </div>
</section>
@import "tailwindcss";

@theme {
  --color-tih13-bg: #0a0906;
  --color-tih13-bg: oklch(0.12 0.008 85);
  --color-tih13-text: #f1f5f9;
  --color-tih13-text: oklch(0.96 0.005 250);
  --color-tih13-muted: #78716c;
  --color-tih13-muted: oklch(0.6 0.01 60);
  --color-tih13-acc: #fbbf24;
  --color-tih13-acc: oklch(0.84 0.16 85);
  --font-tih13-sans: 'Space Grotesk', system-ui, sans-serif;
  --ease-tih13: cubic-bezier(0.4, 0, 0.2, 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-13 {
  width: 100%;
  min-height: 100svh;
}

.tih-13 ::selection {
  background: oklch(0.84 0.16 85);
  color: #000;
}

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-tih13-bg: #0a0906;
  --color-tih13-bg: oklch(0.12 0.008 85);
  --color-tih13-text: #f1f5f9;
  --color-tih13-text: oklch(0.96 0.005 250);
  --color-tih13-muted: #78716c;
  --color-tih13-muted: oklch(0.6 0.01 60);
  --color-tih13-acc: #fbbf24;
  --color-tih13-acc: oklch(0.84 0.16 85);
  --font-tih13-sans: 'Space Grotesk', system-ui, sans-serif;
  --ease-tih13: cubic-bezier(0.4, 0, 0.2, 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-13 {
  width: 100%;
  min-height: 100svh;
}

.tih-13 ::selection {
  background: oklch(0.84 0.16 85);
  color: #000;
}
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.

  • An entire ::after rule plus its hover rule become one after: variant chain — eleven utilities, all on the element that owns the sheen. This is the collection's best case for pseudo-element variants.
  • The five-stop gradient stays one arbitrary value. Stops are a tuned curve, not tokens, and splitting them would make the band harder to read, not easier.
  • after:transition-[translate] rather than transition-transform: the skew is a separate individual property now, and naming transform would animate nothing.
  • after:-inset-1/2 plus after:w-2/5 after:h-[200%] replaces four declarations, and the oversize box is now visibly intentional rather than a magic inset:-50%.
  • motion-reduce:after:hidden matches the CSS version's display:none exactly, in one utility, with no repeated selector.
  • The class list is long — honestly long. This is the demo where a component wrapper (not @apply) is the right answer in a real codebase.
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 Shining Light Glare Image Hover
Source: https://codefronts.com/motion/tailwind-css-image-hover-effects/tailwind-shining-light-glare-image-hover/

A bright band swept across the artwork by a single pseudo-element &mdash; and in utilities the entire sweep is an after: chain on the frame: after:[translate:-200%] group-hover:after:[translate:300%]. No extra markup, no separate rule block, and the two ends of the travel sit next to each other.
## HTML
```html
<section class="tih-13 w-full min-h-svh grid place-items-center bg-tih13-bg font-tih13-sans px-6 py-10" aria-label="Shining light glare 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-[14px] border border-[oklch(1_0_0/0.06)] transition-[border-color,box-shadow] duration-600 ease-tih13 hover:border-[oklch(0.84_0.16_85/0.3)] hover:shadow-[0_8px_40px_oklch(0.84_0.16_85/0.12)] motion-reduce:transition-none">
      <div class="relative aspect-[4/3] grid place-items-center overflow-hidden bg-[image:url('https://picsum.photos/seed/tih13-gold/800/600'),linear-gradient(135deg,oklch(0.18_0.03_60),oklch(0.32_0.08_55),oklch(0.55_0.13_65),oklch(0.84_0.16_85))] bg-cover bg-center bg-no-repeat after:content-[''] after:absolute after:-inset-1/2 after:w-2/5 after:h-[200%] after:bg-linear-[105deg,transparent_40%,oklch(1_0_0/0.08)_45%,oklch(1_0_0/0.22)_50%,oklch(1_0_0/0.08)_55%,transparent_60%] after:skew-x-[-10deg] after:[translate:-200%] after:transition-[translate] after:duration-600 after:ease-tih13 group-hover:after:[translate:300%] motion-reduce:after:hidden">
      </div>
      <div class="px-4 py-3.5 bg-[oklch(0_0_0/0.4)]">
        <p class="mb-1.25 text-[9px] font-bold tracking-[0.12em] uppercase text-tih13-acc">Premium</p>
        <h3 class="text-sm font-bold text-tih13-text">Gold Tier Membership</h3>
        <p class="mt-0.5 text-[11px] tracking-[-1px] text-tih13-acc" aria-label="Rated 5 out of 5">&#9733;&#9733;&#9733;&#9733;&#9733;</p>
        <p class="mt-1.5 text-base font-extrabold text-tih13-acc tabular-nums">$49 / mo</p>
      </div>
    </article>
    <article class="group relative overflow-hidden rounded-[14px] border border-[oklch(1_0_0/0.06)] transition-[border-color,box-shadow] duration-600 ease-tih13 hover:border-[oklch(0.84_0.16_85/0.3)] hover:shadow-[0_8px_40px_oklch(0.84_0.16_85/0.12)] motion-reduce:transition-none">
      <div class="relative aspect-[4/3] grid place-items-center overflow-hidden bg-[image:url('https://picsum.photos/seed/tih13-platinum/800/600'),linear-gradient(135deg,oklch(0.15_0_0),oklch(0.25_0_0),oklch(0.4_0_0),oklch(0.72_0_0))] bg-cover bg-center bg-no-repeat after:content-[''] after:absolute after:-inset-1/2 after:w-2/5 after:h-[200%] after:bg-linear-[105deg,transparent_40%,oklch(1_0_0/0.08)_45%,oklch(1_0_0/0.22)_50%,oklch(1_0_0/0.08)_55%,transparent_60%] after:skew-x-[-10deg] after:[translate:-200%] after:transition-[translate] after:duration-600 after:ease-tih13 group-hover:after:[translate:300%] motion-reduce:after:hidden">
      </div>
      <div class="px-4 py-3.5 bg-[oklch(0_0_0/0.4)]">
        <p class="mb-1.25 text-[9px] font-bold tracking-[0.12em] uppercase text-tih13-acc">Exclusive</p>
        <h3 class="text-sm font-bold text-tih13-text">Platinum Credit Card</h3>
        <p class="mt-0.5 text-[11px] tracking-[-1px] text-tih13-acc" aria-label="Rated 5 out of 5">&#9733;&#9733;&#9733;&#9733;&#9733;</p>
        <p class="mt-1.5 text-base font-extrabold text-tih13-acc tabular-nums">0% APR 18mo</p>
      </div>
    </article>
    <article class="group relative overflow-hidden rounded-[14px] border border-[oklch(1_0_0/0.06)] transition-[border-color,box-shadow] duration-600 ease-tih13 hover:border-[oklch(0.84_0.16_85/0.3)] hover:shadow-[0_8px_40px_oklch(0.84_0.16_85/0.12)] motion-reduce:transition-none">
      <div class="relative aspect-[4/3] grid place-items-center overflow-hidden bg-[image:url('https://picsum.photos/seed/tih13-diamond/800/600'),linear-gradient(135deg,oklch(0.17_0.07_310),oklch(0.35_0.18_295),oklch(0.55_0.24_295),oklch(0.83_0.1_295))] bg-cover bg-center bg-no-repeat after:content-[''] after:absolute after:-inset-1/2 after:w-2/5 after:h-[200%] after:bg-linear-[105deg,transparent_40%,oklch(1_0_0/0.08)_45%,oklch(1_0_0/0.22)_50%,oklch(1_0_0/0.08)_55%,transparent_60%] after:skew-x-[-10deg] after:[translate:-200%] after:transition-[translate] after:duration-600 after:ease-tih13 group-hover:after:[translate:300%] motion-reduce:after:hidden">
      </div>
      <div class="px-4 py-3.5 bg-[oklch(0_0_0/0.4)]">
        <p class="mb-1.25 text-[9px] font-bold tracking-[0.12em] uppercase text-tih13-acc">Diamond</p>
        <h3 class="text-sm font-bold text-tih13-text">Crystal Pro Bundle</h3>
        <p class="mt-0.5 text-[11px] tracking-[-1px] text-tih13-acc" aria-label="Rated 5 out of 5">&#9733;&#9733;&#9733;&#9733;&#9733;</p>
        <p class="mt-1.5 text-base font-extrabold text-tih13-acc tabular-nums">$299 / yr</p>
      </div>
    </article>
  </div>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-tih13-bg: #0a0906;
  --color-tih13-bg: oklch(0.12 0.008 85);
  --color-tih13-text: #f1f5f9;
  --color-tih13-text: oklch(0.96 0.005 250);
  --color-tih13-muted: #78716c;
  --color-tih13-muted: oklch(0.6 0.01 60);
  --color-tih13-acc: #fbbf24;
  --color-tih13-acc: oklch(0.84 0.16 85);
  --font-tih13-sans: 'Space Grotesk', system-ui, sans-serif;
  --ease-tih13: cubic-bezier(0.4, 0, 0.2, 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-13 {
  width: 100%;
  min-height: 100svh;
}

.tih-13 ::selection {
  background: oklch(0.84 0.16 85);
  color: #000;
}
```

How this works

The whole effect is one variant chain.

class="relative overflow-hidden
  after:content-[''] after:absolute after:-inset-1/2 after:w-2/5 after:h-[200%]
  after:bg-linear-[105deg,transparent_40%,…,transparent_60%]
  after:skew-x-[-10deg] after:[translate:-200%]
  after:transition-[translate] after:duration-600
  group-hover:after:[translate:300%]"

Tailwind's pseudo-element variants are what make this port worth doing: the sheen's size, gradient, tilt, resting position and travel are all on the element that owns it, in the order they matter.

Why transition, not animation. A transition restarts cleanly from the left on every re-hover; a keyframe animation needs retriggering gymnastics. The CSS version makes the same call, and the port keeps it.

Only translate animates. after:transition-[translate] means the gradient, the skew and the size never re-interpolate — the sweep is one compositor property moving.

Make it yours

  • Band softness: widen the gradient stops from 40/50/60 to 30/50/70.
  • Cinematic pace: after:duration-900 after:ease-in-out.
  • Always-on: add an --animate-tih13-sweep @theme entry and swap the hover pair for after:animate-tih13-sweep.
  • Dark artwork: raise the peak stop to oklch(1_0_0/0.4).
  • Second softer layer: a before: chain at 15% opacity and a longer duration gives a multi-layer flare.

Gotchas — read before shipping

  • after:content-[''] is mandatory — without it nothing renders and the class list looks correct.
  • The frame needs overflow-hidden or the sheen sweeps out over the page.
  • Keep the sweep box oversized (-inset-1/2, h-[200%]) so the band fully clears both edges; a tight box shows the band appearing mid-card.
  • Do not add a filter to the pseudo-element — it creates a stacking context on the parent and can reorder siblings.
  • Negative arbitrary values go inside the brackets (after:skew-x-[-10deg]), not as a leading minus on the variant.
  • 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+

Transforms on pseudo-elements need no prefixes in any modern engine; the sweep is removed automatically under prefers-reduced-motion.

Techniques used in this demo

Search CodeFronts

Loading…