08 / 20
All 20 in 20 Tailwind CSS Image Hover Effects
- 01Tailwind Image Hover Zoom In Card
- 02Tailwind Hover Reveal Text Over Image
- 03Tailwind E-Commerce Product Image Swap on Hover
- 04Tailwind Grid Image Blur Overlay Text Hover
- 05Tailwind Card Slide Up Caption on Hover
- 06Tailwind Grayscale to Color Image Hover
- 07Tailwind Image Color Overlay Tint on Hover
- 08Tailwind Neumorphic Image Card Hover Effect
- 09Tailwind Glassmorphism Overlay on Image Hover
- 10Tailwind Glowing Neon Border Image Hover
- 11Tailwind Image Clip-Path Transition Hover
- 12Tailwind Image Tilt 3D Perspective Hover
- 13Tailwind Shining Light Glare Image Hover
- 14Tailwind Image Split Transition Hover
- 15Tailwind Image Ripple Animation Hover
- 16Tailwind Circular Team Profile Avatar Hover
- 17Tailwind Fullscreen Background Image Hover
- 18Tailwind Masonry Gallery Zoom Hover
- 19Tailwind Image Icon Reveal Center Hover
- 20Tailwind Image Card Flip 3D Animation Hover
Tailwind Neumorphic Image Card Hover Effect
Soft UI is two shadows going in opposite directions, and the port's win is that they become tokens: --shadow-tih08-out and --shadow-tih08-in in @theme mint shadow-tih08-out and shadow-tih08-in, so the raised and pressed states are named rather than re-typed as eight-value strings on every card and button.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tih-08 w-full min-h-svh grid place-items-center bg-tih08-nm font-tih08-sans px-6 py-10" aria-label="Neumorphic image card hover demo">
<div class="grid w-full max-w-195 gap-6 grid-cols-1 sm:grid-cols-3">
<article class="group p-3 rounded-[20px] bg-tih08-nm shadow-tih08-out transition-[box-shadow,scale] duration-400 ease-tih08 hover:shadow-tih08-in hover:scale-98 motion-reduce:transition-none">
<div class="relative aspect-square overflow-hidden rounded-xl shadow-tih08-well">
<div class="absolute inset-0 grid place-items-center bg-[image:url('https://picsum.photos/seed/tih08-controller/600/600'),linear-gradient(135deg,oklch(0.22_0.09_285),oklch(0.31_0.14_280),oklch(0.45_0.19_275))] bg-cover bg-center bg-no-repeat transition-transform duration-400 ease-tih08 group-hover:scale-104 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
</div>
</div>
<div class="pt-3 px-1">
<h3 class="mb-0.75 text-[13px] font-bold text-tih08-text">Phantom Controller</h3>
<p class="text-[11px] text-tih08-muted">Haptic · Wireless · 40h</p>
<div class="flex items-center justify-between mt-2.5">
<span class="text-[15px] font-bold text-tih08-acc tabular-nums">$89</span>
<button type="button" class="px-3 py-1.25 rounded-full text-[10px] font-bold tracking-[0.06em] text-tih08-text bg-tih08-nm shadow-tih08-btn cursor-pointer transition-shadow duration-200 hover:shadow-tih08-in focus-visible:outline-2 focus-visible:outline-tih08-acc focus-visible:outline-offset-2 motion-reduce:transition-none">Add to Cart</button>
</div>
</div>
</article>
<article class="group p-3 rounded-[20px] bg-tih08-nm shadow-tih08-out transition-[box-shadow,scale] duration-400 ease-tih08 hover:shadow-tih08-in hover:scale-98 motion-reduce:transition-none">
<div class="relative aspect-square overflow-hidden rounded-xl shadow-tih08-well">
<div class="absolute inset-0 grid place-items-center bg-[image:url('https://picsum.photos/seed/tih08-headphones/600/600'),linear-gradient(135deg,oklch(0.29_0.07_240),oklch(0.38_0.1_238),oklch(0.75_0.12_230))] bg-cover bg-center bg-no-repeat transition-transform duration-400 ease-tih08 group-hover:scale-104 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
</div>
</div>
<div class="pt-3 px-1">
<h3 class="mb-0.75 text-[13px] font-bold text-tih08-text">AquaTone Studio</h3>
<p class="text-[11px] text-tih08-muted">ANC · Hi-Res · 60h</p>
<div class="flex items-center justify-between mt-2.5">
<span class="text-[15px] font-bold text-tih08-acc tabular-nums">$229</span>
<button type="button" class="px-3 py-1.25 rounded-full text-[10px] font-bold tracking-[0.06em] text-tih08-text bg-tih08-nm shadow-tih08-btn cursor-pointer transition-shadow duration-200 hover:shadow-tih08-in focus-visible:outline-2 focus-visible:outline-tih08-acc focus-visible:outline-offset-2 motion-reduce:transition-none">Add to Cart</button>
</div>
</div>
</article>
<article class="group p-3 rounded-[20px] bg-tih08-nm shadow-tih08-out transition-[box-shadow,scale] duration-400 ease-tih08 hover:shadow-tih08-in hover:scale-98 motion-reduce:transition-none">
<div class="relative aspect-square overflow-hidden rounded-xl shadow-tih08-well">
<div class="absolute inset-0 grid place-items-center bg-[image:url('https://picsum.photos/seed/tih08-laptop/600/600'),linear-gradient(135deg,oklch(0.25_0.13_305),oklch(0.4_0.2_300),oklch(0.63_0.21_300))] bg-cover bg-center bg-no-repeat transition-transform duration-400 ease-tih08 group-hover:scale-104 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
</div>
</div>
<div class="pt-3 px-1">
<h3 class="mb-0.75 text-[13px] font-bold text-tih08-text">NovaPad Ultra</h3>
<p class="text-[11px] text-tih08-muted">OLED · 12-core · 18h</p>
<div class="flex items-center justify-between mt-2.5">
<span class="text-[15px] font-bold text-tih08-acc tabular-nums">$1,299</span>
<button type="button" class="px-3 py-1.25 rounded-full text-[10px] font-bold tracking-[0.06em] text-tih08-text bg-tih08-nm shadow-tih08-btn cursor-pointer transition-shadow duration-200 hover:shadow-tih08-in focus-visible:outline-2 focus-visible:outline-tih08-acc focus-visible:outline-offset-2 motion-reduce:transition-none">Add to Cart</button>
</div>
</div>
</article>
</div>
</section><section class="tih-08 w-full min-h-svh grid place-items-center bg-tih08-nm font-tih08-sans px-6 py-10" aria-label="Neumorphic image card hover demo">
<div class="grid w-full max-w-195 gap-6 grid-cols-1 sm:grid-cols-3">
<article class="group p-3 rounded-[20px] bg-tih08-nm shadow-tih08-out transition-[box-shadow,scale] duration-400 ease-tih08 hover:shadow-tih08-in hover:scale-98 motion-reduce:transition-none">
<div class="relative aspect-square overflow-hidden rounded-xl shadow-tih08-well">
<div class="absolute inset-0 grid place-items-center bg-[image:url('https://picsum.photos/seed/tih08-controller/600/600'),linear-gradient(135deg,oklch(0.22_0.09_285),oklch(0.31_0.14_280),oklch(0.45_0.19_275))] bg-cover bg-center bg-no-repeat transition-transform duration-400 ease-tih08 group-hover:scale-104 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
</div>
</div>
<div class="pt-3 px-1">
<h3 class="mb-0.75 text-[13px] font-bold text-tih08-text">Phantom Controller</h3>
<p class="text-[11px] text-tih08-muted">Haptic · Wireless · 40h</p>
<div class="flex items-center justify-between mt-2.5">
<span class="text-[15px] font-bold text-tih08-acc tabular-nums">$89</span>
<button type="button" class="px-3 py-1.25 rounded-full text-[10px] font-bold tracking-[0.06em] text-tih08-text bg-tih08-nm shadow-tih08-btn cursor-pointer transition-shadow duration-200 hover:shadow-tih08-in focus-visible:outline-2 focus-visible:outline-tih08-acc focus-visible:outline-offset-2 motion-reduce:transition-none">Add to Cart</button>
</div>
</div>
</article>
<article class="group p-3 rounded-[20px] bg-tih08-nm shadow-tih08-out transition-[box-shadow,scale] duration-400 ease-tih08 hover:shadow-tih08-in hover:scale-98 motion-reduce:transition-none">
<div class="relative aspect-square overflow-hidden rounded-xl shadow-tih08-well">
<div class="absolute inset-0 grid place-items-center bg-[image:url('https://picsum.photos/seed/tih08-headphones/600/600'),linear-gradient(135deg,oklch(0.29_0.07_240),oklch(0.38_0.1_238),oklch(0.75_0.12_230))] bg-cover bg-center bg-no-repeat transition-transform duration-400 ease-tih08 group-hover:scale-104 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
</div>
</div>
<div class="pt-3 px-1">
<h3 class="mb-0.75 text-[13px] font-bold text-tih08-text">AquaTone Studio</h3>
<p class="text-[11px] text-tih08-muted">ANC · Hi-Res · 60h</p>
<div class="flex items-center justify-between mt-2.5">
<span class="text-[15px] font-bold text-tih08-acc tabular-nums">$229</span>
<button type="button" class="px-3 py-1.25 rounded-full text-[10px] font-bold tracking-[0.06em] text-tih08-text bg-tih08-nm shadow-tih08-btn cursor-pointer transition-shadow duration-200 hover:shadow-tih08-in focus-visible:outline-2 focus-visible:outline-tih08-acc focus-visible:outline-offset-2 motion-reduce:transition-none">Add to Cart</button>
</div>
</div>
</article>
<article class="group p-3 rounded-[20px] bg-tih08-nm shadow-tih08-out transition-[box-shadow,scale] duration-400 ease-tih08 hover:shadow-tih08-in hover:scale-98 motion-reduce:transition-none">
<div class="relative aspect-square overflow-hidden rounded-xl shadow-tih08-well">
<div class="absolute inset-0 grid place-items-center bg-[image:url('https://picsum.photos/seed/tih08-laptop/600/600'),linear-gradient(135deg,oklch(0.25_0.13_305),oklch(0.4_0.2_300),oklch(0.63_0.21_300))] bg-cover bg-center bg-no-repeat transition-transform duration-400 ease-tih08 group-hover:scale-104 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
</div>
</div>
<div class="pt-3 px-1">
<h3 class="mb-0.75 text-[13px] font-bold text-tih08-text">NovaPad Ultra</h3>
<p class="text-[11px] text-tih08-muted">OLED · 12-core · 18h</p>
<div class="flex items-center justify-between mt-2.5">
<span class="text-[15px] font-bold text-tih08-acc tabular-nums">$1,299</span>
<button type="button" class="px-3 py-1.25 rounded-full text-[10px] font-bold tracking-[0.06em] text-tih08-text bg-tih08-nm shadow-tih08-btn cursor-pointer transition-shadow duration-200 hover:shadow-tih08-in focus-visible:outline-2 focus-visible:outline-tih08-acc focus-visible:outline-offset-2 motion-reduce:transition-none">Add to Cart</button>
</div>
</div>
</article>
</div>
</section>@import "tailwindcss";
@theme {
--color-tih08-nm: #1e1e2a;
--color-tih08-nm: oklch(0.22 0.02 285);
--color-tih08-text: #e2e8f0;
--color-tih08-text: oklch(0.92 0.01 250);
--color-tih08-muted: #64748b;
--color-tih08-muted: oklch(0.6 0.035 255);
--color-tih08-acc: #6366f1;
--color-tih08-acc: oklch(0.62 0.2 275);
--font-tih08-sans: 'Space Grotesk', system-ui, sans-serif;
--ease-tih08: cubic-bezier(0.25, 0.46, 0.45, 0.94);
--shadow-tih08-out: 6px 6px 16px oklch(0 0 0 / 0.45), -4px -4px 12px oklch(1 0 0 / 0.05);
--shadow-tih08-in: inset 4px 4px 10px oklch(0 0 0 / 0.45), inset -3px -3px 8px oklch(1 0 0 / 0.05);
--shadow-tih08-well: inset 2px 2px 6px oklch(0 0 0 / 0.45), inset -1px -1px 4px oklch(1 0 0 / 0.05);
--shadow-tih08-btn: 3px 3px 8px oklch(0 0 0 / 0.45), -2px -2px 6px oklch(1 0 0 / 0.05);
}
/* 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-08 {
width: 100%;
min-height: 100svh;
}
.tih-08 ::selection {
background: oklch(0.62 0.2 275);
color: #fff;
}
/* Safari inset-shadow-against-radius stability fix: a zero-alpha hairline border.
No utility expresses "border that exists only to stabilise a repaint". */
.tih-08 [class*="rounded-"] {
border: 1px solid transparent;
}@import "tailwindcss";
@theme {
--color-tih08-nm: #1e1e2a;
--color-tih08-nm: oklch(0.22 0.02 285);
--color-tih08-text: #e2e8f0;
--color-tih08-text: oklch(0.92 0.01 250);
--color-tih08-muted: #64748b;
--color-tih08-muted: oklch(0.6 0.035 255);
--color-tih08-acc: #6366f1;
--color-tih08-acc: oklch(0.62 0.2 275);
--font-tih08-sans: 'Space Grotesk', system-ui, sans-serif;
--ease-tih08: cubic-bezier(0.25, 0.46, 0.45, 0.94);
--shadow-tih08-out: 6px 6px 16px oklch(0 0 0 / 0.45), -4px -4px 12px oklch(1 0 0 / 0.05);
--shadow-tih08-in: inset 4px 4px 10px oklch(0 0 0 / 0.45), inset -3px -3px 8px oklch(1 0 0 / 0.05);
--shadow-tih08-well: inset 2px 2px 6px oklch(0 0 0 / 0.45), inset -1px -1px 4px oklch(1 0 0 / 0.05);
--shadow-tih08-btn: 3px 3px 8px oklch(0 0 0 / 0.45), -2px -2px 6px oklch(1 0 0 / 0.05);
}
/* 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-08 {
width: 100%;
min-height: 100svh;
}
.tih-08 ::selection {
background: oklch(0.62 0.2 275);
color: #fff;
}
/* Safari inset-shadow-against-radius stability fix: a zero-alpha hairline border.
No utility expresses "border that exists only to stabilise a repaint". */
.tih-08 [class*="rounded-"] {
border: 1px solid transparent;
}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-tih08-nm: #1e1e2a;
--color-tih08-nm: oklch(0.22 0.02 285);
--color-tih08-text: #e2e8f0;
--color-tih08-text: oklch(0.92 0.01 250);
--color-tih08-muted: #64748b;
--color-tih08-muted: oklch(0.6 0.035 255);
--color-tih08-acc: #6366f1;
--color-tih08-acc: oklch(0.62 0.2 275);
--font-tih08-sans: 'Space Grotesk', system-ui, sans-serif;
--ease-tih08: cubic-bezier(0.25, 0.46, 0.45, 0.94);
--shadow-tih08-out: 6px 6px 16px oklch(0 0 0 / 0.45), -4px -4px 12px oklch(1 0 0 / 0.05);
--shadow-tih08-in: inset 4px 4px 10px oklch(0 0 0 / 0.45), inset -3px -3px 8px oklch(1 0 0 / 0.05);
--shadow-tih08-well: inset 2px 2px 6px oklch(0 0 0 / 0.45), inset -1px -1px 4px oklch(1 0 0 / 0.05);
--shadow-tih08-btn: 3px 3px 8px oklch(0 0 0 / 0.45), -2px -2px 6px oklch(1 0 0 / 0.05);
}
/* 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-08 {
width: 100%;
min-height: 100svh;
}
.tih-08 ::selection {
background: oklch(0.62 0.2 275);
color: #fff;
}
/* Safari inset-shadow-against-radius stability fix: a zero-alpha hairline border.
No utility expresses "border that exists only to stabilise a repaint". */
.tih-08 [class*="rounded-"] {
border: 1px solid transparent;
}@import "tailwindcss";
@theme {
--color-tih08-nm: #1e1e2a;
--color-tih08-nm: oklch(0.22 0.02 285);
--color-tih08-text: #e2e8f0;
--color-tih08-text: oklch(0.92 0.01 250);
--color-tih08-muted: #64748b;
--color-tih08-muted: oklch(0.6 0.035 255);
--color-tih08-acc: #6366f1;
--color-tih08-acc: oklch(0.62 0.2 275);
--font-tih08-sans: 'Space Grotesk', system-ui, sans-serif;
--ease-tih08: cubic-bezier(0.25, 0.46, 0.45, 0.94);
--shadow-tih08-out: 6px 6px 16px oklch(0 0 0 / 0.45), -4px -4px 12px oklch(1 0 0 / 0.05);
--shadow-tih08-in: inset 4px 4px 10px oklch(0 0 0 / 0.45), inset -3px -3px 8px oklch(1 0 0 / 0.05);
--shadow-tih08-well: inset 2px 2px 6px oklch(0 0 0 / 0.45), inset -1px -1px 4px oklch(1 0 0 / 0.05);
--shadow-tih08-btn: 3px 3px 8px oklch(0 0 0 / 0.45), -2px -2px 6px oklch(1 0 0 / 0.05);
}
/* 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-08 {
width: 100%;
min-height: 100svh;
}
.tih-08 ::selection {
background: oklch(0.62 0.2 275);
color: #fff;
}
/* Safari inset-shadow-against-radius stability fix: a zero-alpha hairline border.
No utility expresses "border that exists only to stabilise a repaint". */
.tih-08 [class*="rounded-"] {
border: 1px solid transparent;
}<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">
<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.
- Four shadow strings become four
@themeentries and therefore four utilities. This is the collection's best argument for@themebeyond colour:hover:shadow-tih08-insays what it means, and an eight-value arbitrary string does not. - The page and card share
bg-tih08-nm, so the neumorphic illusion's single hard requirement is enforced by the token system rather than by discipline. transition-[box-shadow,scale]replaces the CSS version'sbox-shadow, transformpair — v4'sscale-*compiles to the individualscaleproperty, so that is the property to name.- The button's raised/pressed pair reuses two of the same tokens, so a light-direction change propagates to it for free.
- The
focus-visible:outline is added by the port. Soft UI has no contrast affordance at all, and shipping it without a focus ring is the actual accessibility failure — not the shadows. - Only the root rule,
::selectionand the Safari hairline shim remain in CSS; the shim is a bug workaround, which is exactly the category that should not be a utility.
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 Neumorphic Image Card Hover Effect
Source: https://codefronts.com/motion/tailwind-css-image-hover-effects/tailwind-neumorphic-image-card-hover-effect/
Soft UI is two shadows going in opposite directions, and the port's win is that they become tokens: --shadow-tih08-out and --shadow-tih08-in in @theme mint shadow-tih08-out and shadow-tih08-in, so the raised and pressed states are named rather than re-typed as eight-value strings on every card and button.
## HTML
```html
<section class="tih-08 w-full min-h-svh grid place-items-center bg-tih08-nm font-tih08-sans px-6 py-10" aria-label="Neumorphic image card hover demo">
<div class="grid w-full max-w-195 gap-6 grid-cols-1 sm:grid-cols-3">
<article class="group p-3 rounded-[20px] bg-tih08-nm shadow-tih08-out transition-[box-shadow,scale] duration-400 ease-tih08 hover:shadow-tih08-in hover:scale-98 motion-reduce:transition-none">
<div class="relative aspect-square overflow-hidden rounded-xl shadow-tih08-well">
<div class="absolute inset-0 grid place-items-center bg-[image:url('https://picsum.photos/seed/tih08-controller/600/600'),linear-gradient(135deg,oklch(0.22_0.09_285),oklch(0.31_0.14_280),oklch(0.45_0.19_275))] bg-cover bg-center bg-no-repeat transition-transform duration-400 ease-tih08 group-hover:scale-104 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
</div>
</div>
<div class="pt-3 px-1">
<h3 class="mb-0.75 text-[13px] font-bold text-tih08-text">Phantom Controller</h3>
<p class="text-[11px] text-tih08-muted">Haptic · Wireless · 40h</p>
<div class="flex items-center justify-between mt-2.5">
<span class="text-[15px] font-bold text-tih08-acc tabular-nums">$89</span>
<button type="button" class="px-3 py-1.25 rounded-full text-[10px] font-bold tracking-[0.06em] text-tih08-text bg-tih08-nm shadow-tih08-btn cursor-pointer transition-shadow duration-200 hover:shadow-tih08-in focus-visible:outline-2 focus-visible:outline-tih08-acc focus-visible:outline-offset-2 motion-reduce:transition-none">Add to Cart</button>
</div>
</div>
</article>
<article class="group p-3 rounded-[20px] bg-tih08-nm shadow-tih08-out transition-[box-shadow,scale] duration-400 ease-tih08 hover:shadow-tih08-in hover:scale-98 motion-reduce:transition-none">
<div class="relative aspect-square overflow-hidden rounded-xl shadow-tih08-well">
<div class="absolute inset-0 grid place-items-center bg-[image:url('https://picsum.photos/seed/tih08-headphones/600/600'),linear-gradient(135deg,oklch(0.29_0.07_240),oklch(0.38_0.1_238),oklch(0.75_0.12_230))] bg-cover bg-center bg-no-repeat transition-transform duration-400 ease-tih08 group-hover:scale-104 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
</div>
</div>
<div class="pt-3 px-1">
<h3 class="mb-0.75 text-[13px] font-bold text-tih08-text">AquaTone Studio</h3>
<p class="text-[11px] text-tih08-muted">ANC · Hi-Res · 60h</p>
<div class="flex items-center justify-between mt-2.5">
<span class="text-[15px] font-bold text-tih08-acc tabular-nums">$229</span>
<button type="button" class="px-3 py-1.25 rounded-full text-[10px] font-bold tracking-[0.06em] text-tih08-text bg-tih08-nm shadow-tih08-btn cursor-pointer transition-shadow duration-200 hover:shadow-tih08-in focus-visible:outline-2 focus-visible:outline-tih08-acc focus-visible:outline-offset-2 motion-reduce:transition-none">Add to Cart</button>
</div>
</div>
</article>
<article class="group p-3 rounded-[20px] bg-tih08-nm shadow-tih08-out transition-[box-shadow,scale] duration-400 ease-tih08 hover:shadow-tih08-in hover:scale-98 motion-reduce:transition-none">
<div class="relative aspect-square overflow-hidden rounded-xl shadow-tih08-well">
<div class="absolute inset-0 grid place-items-center bg-[image:url('https://picsum.photos/seed/tih08-laptop/600/600'),linear-gradient(135deg,oklch(0.25_0.13_305),oklch(0.4_0.2_300),oklch(0.63_0.21_300))] bg-cover bg-center bg-no-repeat transition-transform duration-400 ease-tih08 group-hover:scale-104 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
</div>
</div>
<div class="pt-3 px-1">
<h3 class="mb-0.75 text-[13px] font-bold text-tih08-text">NovaPad Ultra</h3>
<p class="text-[11px] text-tih08-muted">OLED · 12-core · 18h</p>
<div class="flex items-center justify-between mt-2.5">
<span class="text-[15px] font-bold text-tih08-acc tabular-nums">$1,299</span>
<button type="button" class="px-3 py-1.25 rounded-full text-[10px] font-bold tracking-[0.06em] text-tih08-text bg-tih08-nm shadow-tih08-btn cursor-pointer transition-shadow duration-200 hover:shadow-tih08-in focus-visible:outline-2 focus-visible:outline-tih08-acc focus-visible:outline-offset-2 motion-reduce:transition-none">Add to Cart</button>
</div>
</div>
</article>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tih08-nm: #1e1e2a;
--color-tih08-nm: oklch(0.22 0.02 285);
--color-tih08-text: #e2e8f0;
--color-tih08-text: oklch(0.92 0.01 250);
--color-tih08-muted: #64748b;
--color-tih08-muted: oklch(0.6 0.035 255);
--color-tih08-acc: #6366f1;
--color-tih08-acc: oklch(0.62 0.2 275);
--font-tih08-sans: 'Space Grotesk', system-ui, sans-serif;
--ease-tih08: cubic-bezier(0.25, 0.46, 0.45, 0.94);
--shadow-tih08-out: 6px 6px 16px oklch(0 0 0 / 0.45), -4px -4px 12px oklch(1 0 0 / 0.05);
--shadow-tih08-in: inset 4px 4px 10px oklch(0 0 0 / 0.45), inset -3px -3px 8px oklch(1 0 0 / 0.05);
--shadow-tih08-well: inset 2px 2px 6px oklch(0 0 0 / 0.45), inset -1px -1px 4px oklch(1 0 0 / 0.05);
--shadow-tih08-btn: 3px 3px 8px oklch(0 0 0 / 0.45), -2px -2px 6px oklch(1 0 0 / 0.05);
}
/* 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-08 {
width: 100%;
min-height: 100svh;
}
.tih-08 ::selection {
background: oklch(0.62 0.2 275);
color: #fff;
}
/* Safari inset-shadow-against-radius stability fix: a zero-alpha hairline border.
No utility expresses "border that exists only to stabilise a repaint". */
.tih-08 [class*="rounded-"] {
border: 1px solid transparent;
}
```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 Neumorphic Image Card Hover Effect
Source: https://codefronts.com/motion/tailwind-css-image-hover-effects/tailwind-neumorphic-image-card-hover-effect/
Soft UI is two shadows going in opposite directions, and the port's win is that they become tokens: --shadow-tih08-out and --shadow-tih08-in in @theme mint shadow-tih08-out and shadow-tih08-in, so the raised and pressed states are named rather than re-typed as eight-value strings on every card and button.
## HTML
```html
<section class="tih-08 w-full min-h-svh grid place-items-center bg-tih08-nm font-tih08-sans px-6 py-10" aria-label="Neumorphic image card hover demo">
<div class="grid w-full max-w-195 gap-6 grid-cols-1 sm:grid-cols-3">
<article class="group p-3 rounded-[20px] bg-tih08-nm shadow-tih08-out transition-[box-shadow,scale] duration-400 ease-tih08 hover:shadow-tih08-in hover:scale-98 motion-reduce:transition-none">
<div class="relative aspect-square overflow-hidden rounded-xl shadow-tih08-well">
<div class="absolute inset-0 grid place-items-center bg-[image:url('https://picsum.photos/seed/tih08-controller/600/600'),linear-gradient(135deg,oklch(0.22_0.09_285),oklch(0.31_0.14_280),oklch(0.45_0.19_275))] bg-cover bg-center bg-no-repeat transition-transform duration-400 ease-tih08 group-hover:scale-104 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
</div>
</div>
<div class="pt-3 px-1">
<h3 class="mb-0.75 text-[13px] font-bold text-tih08-text">Phantom Controller</h3>
<p class="text-[11px] text-tih08-muted">Haptic · Wireless · 40h</p>
<div class="flex items-center justify-between mt-2.5">
<span class="text-[15px] font-bold text-tih08-acc tabular-nums">$89</span>
<button type="button" class="px-3 py-1.25 rounded-full text-[10px] font-bold tracking-[0.06em] text-tih08-text bg-tih08-nm shadow-tih08-btn cursor-pointer transition-shadow duration-200 hover:shadow-tih08-in focus-visible:outline-2 focus-visible:outline-tih08-acc focus-visible:outline-offset-2 motion-reduce:transition-none">Add to Cart</button>
</div>
</div>
</article>
<article class="group p-3 rounded-[20px] bg-tih08-nm shadow-tih08-out transition-[box-shadow,scale] duration-400 ease-tih08 hover:shadow-tih08-in hover:scale-98 motion-reduce:transition-none">
<div class="relative aspect-square overflow-hidden rounded-xl shadow-tih08-well">
<div class="absolute inset-0 grid place-items-center bg-[image:url('https://picsum.photos/seed/tih08-headphones/600/600'),linear-gradient(135deg,oklch(0.29_0.07_240),oklch(0.38_0.1_238),oklch(0.75_0.12_230))] bg-cover bg-center bg-no-repeat transition-transform duration-400 ease-tih08 group-hover:scale-104 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
</div>
</div>
<div class="pt-3 px-1">
<h3 class="mb-0.75 text-[13px] font-bold text-tih08-text">AquaTone Studio</h3>
<p class="text-[11px] text-tih08-muted">ANC · Hi-Res · 60h</p>
<div class="flex items-center justify-between mt-2.5">
<span class="text-[15px] font-bold text-tih08-acc tabular-nums">$229</span>
<button type="button" class="px-3 py-1.25 rounded-full text-[10px] font-bold tracking-[0.06em] text-tih08-text bg-tih08-nm shadow-tih08-btn cursor-pointer transition-shadow duration-200 hover:shadow-tih08-in focus-visible:outline-2 focus-visible:outline-tih08-acc focus-visible:outline-offset-2 motion-reduce:transition-none">Add to Cart</button>
</div>
</div>
</article>
<article class="group p-3 rounded-[20px] bg-tih08-nm shadow-tih08-out transition-[box-shadow,scale] duration-400 ease-tih08 hover:shadow-tih08-in hover:scale-98 motion-reduce:transition-none">
<div class="relative aspect-square overflow-hidden rounded-xl shadow-tih08-well">
<div class="absolute inset-0 grid place-items-center bg-[image:url('https://picsum.photos/seed/tih08-laptop/600/600'),linear-gradient(135deg,oklch(0.25_0.13_305),oklch(0.4_0.2_300),oklch(0.63_0.21_300))] bg-cover bg-center bg-no-repeat transition-transform duration-400 ease-tih08 group-hover:scale-104 motion-reduce:transition-none motion-reduce:group-hover:scale-100">
</div>
</div>
<div class="pt-3 px-1">
<h3 class="mb-0.75 text-[13px] font-bold text-tih08-text">NovaPad Ultra</h3>
<p class="text-[11px] text-tih08-muted">OLED · 12-core · 18h</p>
<div class="flex items-center justify-between mt-2.5">
<span class="text-[15px] font-bold text-tih08-acc tabular-nums">$1,299</span>
<button type="button" class="px-3 py-1.25 rounded-full text-[10px] font-bold tracking-[0.06em] text-tih08-text bg-tih08-nm shadow-tih08-btn cursor-pointer transition-shadow duration-200 hover:shadow-tih08-in focus-visible:outline-2 focus-visible:outline-tih08-acc focus-visible:outline-offset-2 motion-reduce:transition-none">Add to Cart</button>
</div>
</div>
</article>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tih08-nm: #1e1e2a;
--color-tih08-nm: oklch(0.22 0.02 285);
--color-tih08-text: #e2e8f0;
--color-tih08-text: oklch(0.92 0.01 250);
--color-tih08-muted: #64748b;
--color-tih08-muted: oklch(0.6 0.035 255);
--color-tih08-acc: #6366f1;
--color-tih08-acc: oklch(0.62 0.2 275);
--font-tih08-sans: 'Space Grotesk', system-ui, sans-serif;
--ease-tih08: cubic-bezier(0.25, 0.46, 0.45, 0.94);
--shadow-tih08-out: 6px 6px 16px oklch(0 0 0 / 0.45), -4px -4px 12px oklch(1 0 0 / 0.05);
--shadow-tih08-in: inset 4px 4px 10px oklch(0 0 0 / 0.45), inset -3px -3px 8px oklch(1 0 0 / 0.05);
--shadow-tih08-well: inset 2px 2px 6px oklch(0 0 0 / 0.45), inset -1px -1px 4px oklch(1 0 0 / 0.05);
--shadow-tih08-btn: 3px 3px 8px oklch(0 0 0 / 0.45), -2px -2px 6px oklch(1 0 0 / 0.05);
}
/* 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-08 {
width: 100%;
min-height: 100svh;
}
.tih-08 ::selection {
background: oklch(0.62 0.2 275);
color: #fff;
}
/* Safari inset-shadow-against-radius stability fix: a zero-alpha hairline border.
No utility expresses "border that exists only to stabilise a repaint". */
.tih-08 [class*="rounded-"] {
border: 1px solid transparent;
}
```How this works
Shadows as design tokens. This is the one demo where @theme earns its keep beyond colour:
@theme {
--shadow-tih08-out: 6px 6px 16px oklch(0 0 0/0.45), -4px -4px 12px oklch(1 0 0/0.05);
--shadow-tih08-in: inset 4px 4px 10px oklch(0 0 0/0.45), inset -3px -3px 8px oklch(1 0 0/0.05);
}The markup then reads shadow-tih08-out hover:shadow-tih08-in. An arbitrary value would work, but the eight-value string would appear five times and the light direction would eventually drift on one of them.
The illusion depends on one colour. The card background and the page background are the same token, so there is no mismatch to introduce. This is the failure mode of every neumorphic component library, and a shared token removes it.
Press is shadow plus scale. hover:scale-98 is a real 2% shrink on the compositor, which is what makes the inset shadow read as a push rather than a repaint.
Make it yours
- Light direction: flip the signs inside the two shadow tokens — both states update together, which is the point of tokenising them.
- Depth: lower the dark alpha to
0.3for lighter surfaces. Edit the token, not the markup. - Spring press:
ease-[cubic-bezier(0.34,1.56,0.64,1)]for a tactile overshoot. - Coloured neumorphism: tint the light shadow with a desaturated surface hue instead of white.
- Retheme through
--color-tih08-nm— and remember to keep the section and the card on that one token.
Gotchas — read before shipping
- The card background MUST equal the page background. Two tokens is one token too many here.
- Neumorphism has no border and no contrast affordance; it fails WCAG on its own. The
focus-visible:outline and the text labels are doing the accessibility work, and they are not optional. - Multi-value shadows in
@themeneed commas and no newlines in the value — a wrapped token value silently fails to parse. hover:scale-98on a card containing a button means the button scales too. Keep the press subtle or the hit target moves under the cursor.- Safari below 14 can clip inset shadows against
rounded-*; a 0-alpha 1px border is the stability fix, and it stays in the stylesheet because no utility expresses that intent. - The browser CDN build compiles in the page and is for prototyping only. Ship the CLI or a plugin build.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
box-shadow with inset is universally supported; the visual result depends on display calibration more than on engine.