21 / 30
All 30 in 30 Tailwind CSS Hover Effects
- 01Tailwind Underline Draw Hover Effect
- 02Tailwind Text Glitch Hover Effect
- 03Tailwind Letter Spacing Expand Hover Effect
- 04Tailwind Gradient Text Reveal Hover Effect
- 05Tailwind Split Text Hover Effect
- 06Tailwind Neon Glow Text Hover Effect
- 07Tailwind Magnetic Liquid Button Hover Effect
- 08Tailwind Border Draw Hover Effect
- 09Tailwind Shimmer Shine Button Hover Effect
- 10Tailwind Fill Wipe Button Hover Effect
- 11Tailwind 3D Press Button Hover Effect
- 12Tailwind Ripple Button Hover Effect
- 13Tailwind 3D Tilt Card Hover Effect
- 14Tailwind Card Flip Hover Effect
- 15Tailwind Glassmorphism Card Hover Effect
- 16Tailwind Spotlight Card Hover Effect
- 17Tailwind Slide Reveal Card Hover Effect
- 18Tailwind Stack Lift Card Hover Effect
- 19Tailwind Zoom Pan Image Hover Effect
- 20Tailwind Color Channel Split Hover Effect
- 21Tailwind Duotone Image Hover Effect
- 22Tailwind Curtain Reveal Image Hover Effect
- 23Tailwind Ken Burns Image Hover Effect
- 24Tailwind Image Tilt Depth Hover Effect
- 25Tailwind Underline Slide Nav Hover Effect
- 26Tailwind Highlight Fill Nav Hover Effect
- 27Tailwind Strikethrough Hover Link Effect
- 28Tailwind Inline Word Swap Hover Effect
- 29Tailwind Dot Trail Cursor Hover Effect
- 30Tailwind Magnetic Cursor Pull Hover Effect
Tailwind Duotone Image Hover Effect
Four colour-grade transitions — grayscale to full colour, duotone to natural, a hue-rotate grade and a desaturate fade-in. grayscale, saturate-* and isolate are all core utilities, so only the filter chains stay arbitrary.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="thv-21 w-full min-h-svh grid place-items-center bg-thv21-bg font-thv21-sans px-6 py-14">
<div class="w-[min(760px,100%)] grid grid-cols-[repeat(auto-fit,minmax(280px,1fr))] gap-8">
<figure class="group flex flex-col gap-3 m-0">
<div class="relative isolate w-full aspect-video overflow-hidden rounded-xl cursor-pointer">
<img src="https://images.unsplash.com/photo-1493809842364-78817add7ffb?auto=format&fit=crop&w=900&q=80" alt="Blue velvet armchair in a bare studio" decoding="async" class="w-full h-full [filter:grayscale(1)_contrast(1.1)] transition-[filter] duration-500 ease-[cubic-bezier(.4,0,.2,1)] group-hover:filter-none object-cover">
</div>
<figcaption class="text-[11px] tracking-[0.12em] uppercase text-thv21-dim">grayscale → colour restore</figcaption>
</figure>
<figure class="group flex flex-col gap-3 m-0">
<div class="relative isolate w-full aspect-video overflow-hidden rounded-xl cursor-pointer">
<img src="https://images.unsplash.com/photo-1618221195710-dd6b41faaea6?auto=format&fit=crop&w=900&q=80" alt="Minimal bedroom with linen bedding and morning light" decoding="async" class="w-full h-full [filter:contrast(1.1)] object-cover">
<div aria-hidden="true" class="absolute inset-0 mix-blend-color opacity-100 transition-opacity duration-500 ease-[cubic-bezier(.4,0,.2,1)] group-hover:opacity-0 bg-[linear-gradient(135deg,#1e003c,#ff6b00)]"></div>
</div>
<figcaption class="text-[11px] tracking-[0.12em] uppercase text-thv21-dim">duotone → natural</figcaption>
</figure>
<figure class="group flex flex-col gap-3 m-0">
<div class="relative isolate w-full aspect-video overflow-hidden rounded-xl cursor-pointer">
<img src="https://images.unsplash.com/photo-1616486338812-3dadae4b4ace?auto=format&fit=crop&w=900&q=80" alt="Concrete and timber staircase in a modern house" decoding="async" class="w-full h-full [filter:hue-rotate(0deg)_saturate(1)] transition-[filter] duration-600 ease-[cubic-bezier(.4,0,.2,1)] group-hover:[filter:hue-rotate(160deg)_saturate(1.5)] object-cover">
</div>
<figcaption class="text-[11px] tracking-[0.12em] uppercase text-thv21-dim">hue-rotate grade</figcaption>
</figure>
<figure class="group flex flex-col gap-3 m-0">
<div class="relative isolate w-full aspect-video overflow-hidden rounded-xl cursor-pointer">
<img src="https://images.unsplash.com/photo-1502005229762-cf1b2da7c5d6?auto=format&fit=crop&w=900&q=80" alt="Reading corner with a low lounge chair and side table" decoding="async" class="w-full h-full grayscale transition-[filter] duration-500 ease-[cubic-bezier(.4,0,.2,1)] group-hover:grayscale-0 group-hover:saturate-125 object-cover">
</div>
<figcaption class="text-[11px] tracking-[0.12em] uppercase text-thv21-dim">desaturate fade-in</figcaption>
</figure>
</div>
</section><section class="thv-21 w-full min-h-svh grid place-items-center bg-thv21-bg font-thv21-sans px-6 py-14">
<div class="w-[min(760px,100%)] grid grid-cols-[repeat(auto-fit,minmax(280px,1fr))] gap-8">
<figure class="group flex flex-col gap-3 m-0">
<div class="relative isolate w-full aspect-video overflow-hidden rounded-xl cursor-pointer">
<img src="https://images.unsplash.com/photo-1493809842364-78817add7ffb?auto=format&fit=crop&w=900&q=80" alt="Blue velvet armchair in a bare studio" decoding="async" class="w-full h-full [filter:grayscale(1)_contrast(1.1)] transition-[filter] duration-500 ease-[cubic-bezier(.4,0,.2,1)] group-hover:filter-none object-cover">
</div>
<figcaption class="text-[11px] tracking-[0.12em] uppercase text-thv21-dim">grayscale → colour restore</figcaption>
</figure>
<figure class="group flex flex-col gap-3 m-0">
<div class="relative isolate w-full aspect-video overflow-hidden rounded-xl cursor-pointer">
<img src="https://images.unsplash.com/photo-1618221195710-dd6b41faaea6?auto=format&fit=crop&w=900&q=80" alt="Minimal bedroom with linen bedding and morning light" decoding="async" class="w-full h-full [filter:contrast(1.1)] object-cover">
<div aria-hidden="true" class="absolute inset-0 mix-blend-color opacity-100 transition-opacity duration-500 ease-[cubic-bezier(.4,0,.2,1)] group-hover:opacity-0 bg-[linear-gradient(135deg,#1e003c,#ff6b00)]"></div>
</div>
<figcaption class="text-[11px] tracking-[0.12em] uppercase text-thv21-dim">duotone → natural</figcaption>
</figure>
<figure class="group flex flex-col gap-3 m-0">
<div class="relative isolate w-full aspect-video overflow-hidden rounded-xl cursor-pointer">
<img src="https://images.unsplash.com/photo-1616486338812-3dadae4b4ace?auto=format&fit=crop&w=900&q=80" alt="Concrete and timber staircase in a modern house" decoding="async" class="w-full h-full [filter:hue-rotate(0deg)_saturate(1)] transition-[filter] duration-600 ease-[cubic-bezier(.4,0,.2,1)] group-hover:[filter:hue-rotate(160deg)_saturate(1.5)] object-cover">
</div>
<figcaption class="text-[11px] tracking-[0.12em] uppercase text-thv21-dim">hue-rotate grade</figcaption>
</figure>
<figure class="group flex flex-col gap-3 m-0">
<div class="relative isolate w-full aspect-video overflow-hidden rounded-xl cursor-pointer">
<img src="https://images.unsplash.com/photo-1502005229762-cf1b2da7c5d6?auto=format&fit=crop&w=900&q=80" alt="Reading corner with a low lounge chair and side table" decoding="async" class="w-full h-full grayscale transition-[filter] duration-500 ease-[cubic-bezier(.4,0,.2,1)] group-hover:grayscale-0 group-hover:saturate-125 object-cover">
</div>
<figcaption class="text-[11px] tracking-[0.12em] uppercase text-thv21-dim">desaturate fade-in</figcaption>
</figure>
</div>
</section>@import "tailwindcss";
@theme {
--color-thv21-bg: #080608;
--color-thv21-bg: oklch(0.11 0.01 320);
--color-thv21-dim: #8e8b90;
--color-thv21-dim: oklch(0.65 0.01 320);
--font-thv21-sans: 'Space Grotesk', system-ui, sans-serif;
}
.thv-21 {
width: 100%;
min-height: 100svh;
}
.thv-21 ::selection {
background: #9333ea;
color: #fff;
}@import "tailwindcss";
@theme {
--color-thv21-bg: #080608;
--color-thv21-bg: oklch(0.11 0.01 320);
--color-thv21-dim: #8e8b90;
--color-thv21-dim: oklch(0.65 0.01 320);
--font-thv21-sans: 'Space Grotesk', system-ui, sans-serif;
}
.thv-21 {
width: 100%;
min-height: 100svh;
}
.thv-21 ::selection {
background: #9333ea;
color: #fff;
}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-thv21-bg: #080608;
--color-thv21-bg: oklch(0.11 0.01 320);
--color-thv21-dim: #8e8b90;
--color-thv21-dim: oklch(0.65 0.01 320);
--font-thv21-sans: 'Space Grotesk', system-ui, sans-serif;
}
.thv-21 {
width: 100%;
min-height: 100svh;
}
.thv-21 ::selection {
background: #9333ea;
color: #fff;
}@import "tailwindcss";
@theme {
--color-thv21-bg: #080608;
--color-thv21-bg: oklch(0.11 0.01 320);
--color-thv21-dim: #8e8b90;
--color-thv21-dim: oklch(0.65 0.01 320);
--font-thv21-sans: 'Space Grotesk', system-ui, sans-serif;
}
.thv-21 {
width: 100%;
min-height: 100svh;
}
.thv-21 ::selection {
background: #9333ea;
color: #fff;
}<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;800&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=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;800&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
grayscale,grayscale-0,saturate-125,isolateandmix-blend-colorare all core utilities — the last variant is written entirely without arbitrary values.- UI change from the CSS original: captions are real
<figcaption>elements at a contrast-passing lightness, and the blend overlays arearia-hidden. - Only the multi-step chains (
grayscale(1) contrast(1.1)) stay arbitrary, because two filter utilities on one element would overwrite each other.
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 Duotone Image Hover Effect
Source: https://codefronts.com/motion/tailwind-css-hover-effects/tailwind-duotone-image-hover-effect/
Four colour-grade transitions — grayscale to full colour, duotone to natural, a hue-rotate grade and a desaturate fade-in. grayscale, saturate-* and isolate are all core utilities, so only the filter chains stay arbitrary.
## HTML
```html
<section class="thv-21 w-full min-h-svh grid place-items-center bg-thv21-bg font-thv21-sans px-6 py-14">
<div class="w-[min(760px,100%)] grid grid-cols-[repeat(auto-fit,minmax(280px,1fr))] gap-8">
<figure class="group flex flex-col gap-3 m-0">
<div class="relative isolate w-full aspect-video overflow-hidden rounded-xl cursor-pointer">
<img src="https://images.unsplash.com/photo-1493809842364-78817add7ffb?auto=format&fit=crop&w=900&q=80" alt="Blue velvet armchair in a bare studio" decoding="async" class="w-full h-full [filter:grayscale(1)_contrast(1.1)] transition-[filter] duration-500 ease-[cubic-bezier(.4,0,.2,1)] group-hover:filter-none object-cover">
</div>
<figcaption class="text-[11px] tracking-[0.12em] uppercase text-thv21-dim">grayscale → colour restore</figcaption>
</figure>
<figure class="group flex flex-col gap-3 m-0">
<div class="relative isolate w-full aspect-video overflow-hidden rounded-xl cursor-pointer">
<img src="https://images.unsplash.com/photo-1618221195710-dd6b41faaea6?auto=format&fit=crop&w=900&q=80" alt="Minimal bedroom with linen bedding and morning light" decoding="async" class="w-full h-full [filter:contrast(1.1)] object-cover">
<div aria-hidden="true" class="absolute inset-0 mix-blend-color opacity-100 transition-opacity duration-500 ease-[cubic-bezier(.4,0,.2,1)] group-hover:opacity-0 bg-[linear-gradient(135deg,#1e003c,#ff6b00)]"></div>
</div>
<figcaption class="text-[11px] tracking-[0.12em] uppercase text-thv21-dim">duotone → natural</figcaption>
</figure>
<figure class="group flex flex-col gap-3 m-0">
<div class="relative isolate w-full aspect-video overflow-hidden rounded-xl cursor-pointer">
<img src="https://images.unsplash.com/photo-1616486338812-3dadae4b4ace?auto=format&fit=crop&w=900&q=80" alt="Concrete and timber staircase in a modern house" decoding="async" class="w-full h-full [filter:hue-rotate(0deg)_saturate(1)] transition-[filter] duration-600 ease-[cubic-bezier(.4,0,.2,1)] group-hover:[filter:hue-rotate(160deg)_saturate(1.5)] object-cover">
</div>
<figcaption class="text-[11px] tracking-[0.12em] uppercase text-thv21-dim">hue-rotate grade</figcaption>
</figure>
<figure class="group flex flex-col gap-3 m-0">
<div class="relative isolate w-full aspect-video overflow-hidden rounded-xl cursor-pointer">
<img src="https://images.unsplash.com/photo-1502005229762-cf1b2da7c5d6?auto=format&fit=crop&w=900&q=80" alt="Reading corner with a low lounge chair and side table" decoding="async" class="w-full h-full grayscale transition-[filter] duration-500 ease-[cubic-bezier(.4,0,.2,1)] group-hover:grayscale-0 group-hover:saturate-125 object-cover">
</div>
<figcaption class="text-[11px] tracking-[0.12em] uppercase text-thv21-dim">desaturate fade-in</figcaption>
</figure>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-thv21-bg: #080608;
--color-thv21-bg: oklch(0.11 0.01 320);
--color-thv21-dim: #8e8b90;
--color-thv21-dim: oklch(0.65 0.01 320);
--font-thv21-sans: 'Space Grotesk', system-ui, sans-serif;
}
.thv-21 {
width: 100%;
min-height: 100svh;
}
.thv-21 ::selection {
background: #9333ea;
color: #fff;
}
```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 Duotone Image Hover Effect
Source: https://codefronts.com/motion/tailwind-css-hover-effects/tailwind-duotone-image-hover-effect/
Four colour-grade transitions — grayscale to full colour, duotone to natural, a hue-rotate grade and a desaturate fade-in. grayscale, saturate-* and isolate are all core utilities, so only the filter chains stay arbitrary.
## HTML
```html
<section class="thv-21 w-full min-h-svh grid place-items-center bg-thv21-bg font-thv21-sans px-6 py-14">
<div class="w-[min(760px,100%)] grid grid-cols-[repeat(auto-fit,minmax(280px,1fr))] gap-8">
<figure class="group flex flex-col gap-3 m-0">
<div class="relative isolate w-full aspect-video overflow-hidden rounded-xl cursor-pointer">
<img src="https://images.unsplash.com/photo-1493809842364-78817add7ffb?auto=format&fit=crop&w=900&q=80" alt="Blue velvet armchair in a bare studio" decoding="async" class="w-full h-full [filter:grayscale(1)_contrast(1.1)] transition-[filter] duration-500 ease-[cubic-bezier(.4,0,.2,1)] group-hover:filter-none object-cover">
</div>
<figcaption class="text-[11px] tracking-[0.12em] uppercase text-thv21-dim">grayscale → colour restore</figcaption>
</figure>
<figure class="group flex flex-col gap-3 m-0">
<div class="relative isolate w-full aspect-video overflow-hidden rounded-xl cursor-pointer">
<img src="https://images.unsplash.com/photo-1618221195710-dd6b41faaea6?auto=format&fit=crop&w=900&q=80" alt="Minimal bedroom with linen bedding and morning light" decoding="async" class="w-full h-full [filter:contrast(1.1)] object-cover">
<div aria-hidden="true" class="absolute inset-0 mix-blend-color opacity-100 transition-opacity duration-500 ease-[cubic-bezier(.4,0,.2,1)] group-hover:opacity-0 bg-[linear-gradient(135deg,#1e003c,#ff6b00)]"></div>
</div>
<figcaption class="text-[11px] tracking-[0.12em] uppercase text-thv21-dim">duotone → natural</figcaption>
</figure>
<figure class="group flex flex-col gap-3 m-0">
<div class="relative isolate w-full aspect-video overflow-hidden rounded-xl cursor-pointer">
<img src="https://images.unsplash.com/photo-1616486338812-3dadae4b4ace?auto=format&fit=crop&w=900&q=80" alt="Concrete and timber staircase in a modern house" decoding="async" class="w-full h-full [filter:hue-rotate(0deg)_saturate(1)] transition-[filter] duration-600 ease-[cubic-bezier(.4,0,.2,1)] group-hover:[filter:hue-rotate(160deg)_saturate(1.5)] object-cover">
</div>
<figcaption class="text-[11px] tracking-[0.12em] uppercase text-thv21-dim">hue-rotate grade</figcaption>
</figure>
<figure class="group flex flex-col gap-3 m-0">
<div class="relative isolate w-full aspect-video overflow-hidden rounded-xl cursor-pointer">
<img src="https://images.unsplash.com/photo-1502005229762-cf1b2da7c5d6?auto=format&fit=crop&w=900&q=80" alt="Reading corner with a low lounge chair and side table" decoding="async" class="w-full h-full grayscale transition-[filter] duration-500 ease-[cubic-bezier(.4,0,.2,1)] group-hover:grayscale-0 group-hover:saturate-125 object-cover">
</div>
<figcaption class="text-[11px] tracking-[0.12em] uppercase text-thv21-dim">desaturate fade-in</figcaption>
</figure>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-thv21-bg: #080608;
--color-thv21-bg: oklch(0.11 0.01 320);
--color-thv21-dim: #8e8b90;
--color-thv21-dim: oklch(0.65 0.01 320);
--font-thv21-sans: 'Space Grotesk', system-ui, sans-serif;
}
.thv-21 {
width: 100%;
min-height: 100svh;
}
.thv-21 ::selection {
background: #9333ea;
color: #fff;
}
```How this works
Duotone is a blend, not a filter. A two-stop gradient at mix-blend-color maps hue onto the image's luminance; fading its opacity to zero restores the original colour. isolate on the wrapper is what stops that blend leaking into the page behind it.
Everything else is a filter chain. Grayscale, hue-rotate and saturate all live in one filter, so they belong in one arbitrary value rather than three utilities fighting over the same property.
Transition the filter, not the layout. transition-[filter] keeps the animation to a single compositable property.
Make it yours
- Retune the duotone by editing the gradient's two stops.
- Editorial pace:
duration-1000; interactive pace:duration-200. - Use
mix-blend-hueinstead ofcolorto keep the original saturation.
Gotchas — read before shipping
- Without
isolate,mix-blend-colorcomposites against the page, not the card. - Apply
grayscaleto the image layer, not to the wrapper that holds the blend overlay — filter and blend order matters. - SVG
feColorMatrixis more faithful for print-grade duotone; this is the UI-grade approximation.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
Filter chains and mix-blend-mode: color are Baseline; the floor is Tailwind v4's generated sheet.