13 / 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 3D Tilt Card Hover Effect
Four perspective cards — fixed diagonal tilt, opposite-axis tilt, a float lift with shadow depth, and translateZ parallax layers. v4 ships perspective-*, transform-3d, rotate-x-* and translate-z-*, so this port needs almost no arbitrary values.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="thv-13 w-full min-h-svh grid place-items-center bg-thv13-bg font-thv13-sans px-6 py-14">
<div class="w-[min(800px,100%)] grid grid-cols-[repeat(auto-fit,minmax(280px,1fr))] gap-10">
<div class="perspective-[800px]">
<button type="button" class="block w-full min-h-[220px] text-left rounded-2xl bg-white/[0.04] border border-white/10 transform-3d cursor-pointer transition-[transform,box-shadow] duration-400 ease-[cubic-bezier(.4,0,.2,1)] hover:rotate-x-[8deg] hover:rotate-y-[-8deg] hover:shadow-[8px_12px_40px_rgba(14,165,233,.3)] focus-visible:rotate-x-[8deg] focus-visible:rotate-y-[-8deg] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv13-blue motion-reduce:transition-none motion-reduce:hover:rotate-x-0 motion-reduce:hover:rotate-y-0 motion-reduce:hover:border-thv13-blue">
<span class="flex flex-col gap-3 p-8">
<span class="text-3xl text-thv13-blue">◈</span>
<span class="text-lg font-bold text-thv13-text">Static Tilt</span>
<span class="text-sm leading-relaxed text-thv13-dim">Perspective rotateX + rotateY on hover.</span>
</span>
</button>
</div>
<div class="perspective-[800px]">
<button type="button" class="block w-full min-h-[220px] text-left rounded-2xl bg-white/[0.04] border border-thv13-indigo/30 transform-3d cursor-pointer transition-[transform,box-shadow,border-color] duration-400 ease-[cubic-bezier(.4,0,.2,1)] hover:rotate-x-[-6deg] hover:rotate-y-[10deg] hover:border-thv13-indigo/60 hover:shadow-[-10px_8px_40px_rgba(99,102,241,.3)] focus-visible:rotate-x-[-6deg] focus-visible:rotate-y-[10deg] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv13-indigo motion-reduce:transition-none motion-reduce:hover:rotate-x-0 motion-reduce:hover:rotate-y-0">
<span class="flex flex-col gap-3 p-8">
<span class="text-3xl text-thv13-indigo">⬡</span>
<span class="text-lg font-bold text-thv13-text">Axis Flip</span>
<span class="text-sm leading-relaxed text-thv13-dim">Opposite-axis lean with a matching cast shadow.</span>
</span>
</button>
</div>
<div>
<button type="button" class="block w-full min-h-[220px] text-left rounded-2xl bg-white/[0.04] border border-thv13-teal/30 shadow-[0_4px_20px_rgba(0,0,0,.4)] cursor-pointer transition-[transform,box-shadow] duration-400 ease-[cubic-bezier(.4,0,.2,1)] hover:-translate-y-[14px] hover:shadow-[0_28px_60px_rgba(0,0,0,.5),0_0_30px_rgba(20,184,166,.2)] focus-visible:-translate-y-[14px] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv13-teal motion-reduce:transition-none motion-reduce:hover:translate-y-0">
<span class="flex flex-col gap-3 p-8">
<span class="text-3xl text-thv13-teal">▲</span>
<span class="text-lg font-bold text-thv13-text">Float Lift</span>
<span class="text-sm leading-relaxed text-thv13-dim">translateY plus a longer cast shadow.</span>
</span>
</button>
</div>
<div class="perspective-[800px]">
<button type="button" class="group relative block w-full min-h-[220px] text-left rounded-2xl bg-white/[0.04] border border-thv13-sky/30 transform-3d cursor-pointer transition-transform duration-400 ease-[cubic-bezier(.4,0,.2,1)] hover:rotate-x-[6deg] hover:rotate-y-[-6deg] focus-visible:rotate-x-[6deg] focus-visible:rotate-y-[-6deg] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv13-sky motion-reduce:transition-none motion-reduce:hover:rotate-x-0 motion-reduce:hover:rotate-y-0">
<span class="absolute inset-0 rounded-2xl bg-[linear-gradient(135deg,rgba(14,165,233,.1),rgba(56,189,248,.05))]"></span>
<span class="absolute inset-0 flex items-start p-8 transition-transform duration-400 ease-[cubic-bezier(.4,0,.2,1)] group-hover:translate-z-[20px] group-hover:-translate-y-1.5 group-focus-visible:translate-z-[20px]"><span class="text-4xl text-thv13-sky">◉</span></span>
<span class="absolute inset-0 flex flex-col justify-end gap-2 p-7 transition-transform duration-400 ease-[cubic-bezier(.4,0,.2,1)] group-hover:translate-z-[35px] group-hover:-translate-y-1 group-focus-visible:translate-z-[35px]">
<span class="text-lg font-bold text-thv13-text">Parallax</span>
<span class="text-sm leading-relaxed text-thv13-dim">translateZ layered depth.</span>
</span>
</button>
</div>
</div>
</section><section class="thv-13 w-full min-h-svh grid place-items-center bg-thv13-bg font-thv13-sans px-6 py-14">
<div class="w-[min(800px,100%)] grid grid-cols-[repeat(auto-fit,minmax(280px,1fr))] gap-10">
<div class="perspective-[800px]">
<button type="button" class="block w-full min-h-[220px] text-left rounded-2xl bg-white/[0.04] border border-white/10 transform-3d cursor-pointer transition-[transform,box-shadow] duration-400 ease-[cubic-bezier(.4,0,.2,1)] hover:rotate-x-[8deg] hover:rotate-y-[-8deg] hover:shadow-[8px_12px_40px_rgba(14,165,233,.3)] focus-visible:rotate-x-[8deg] focus-visible:rotate-y-[-8deg] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv13-blue motion-reduce:transition-none motion-reduce:hover:rotate-x-0 motion-reduce:hover:rotate-y-0 motion-reduce:hover:border-thv13-blue">
<span class="flex flex-col gap-3 p-8">
<span class="text-3xl text-thv13-blue">◈</span>
<span class="text-lg font-bold text-thv13-text">Static Tilt</span>
<span class="text-sm leading-relaxed text-thv13-dim">Perspective rotateX + rotateY on hover.</span>
</span>
</button>
</div>
<div class="perspective-[800px]">
<button type="button" class="block w-full min-h-[220px] text-left rounded-2xl bg-white/[0.04] border border-thv13-indigo/30 transform-3d cursor-pointer transition-[transform,box-shadow,border-color] duration-400 ease-[cubic-bezier(.4,0,.2,1)] hover:rotate-x-[-6deg] hover:rotate-y-[10deg] hover:border-thv13-indigo/60 hover:shadow-[-10px_8px_40px_rgba(99,102,241,.3)] focus-visible:rotate-x-[-6deg] focus-visible:rotate-y-[10deg] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv13-indigo motion-reduce:transition-none motion-reduce:hover:rotate-x-0 motion-reduce:hover:rotate-y-0">
<span class="flex flex-col gap-3 p-8">
<span class="text-3xl text-thv13-indigo">⬡</span>
<span class="text-lg font-bold text-thv13-text">Axis Flip</span>
<span class="text-sm leading-relaxed text-thv13-dim">Opposite-axis lean with a matching cast shadow.</span>
</span>
</button>
</div>
<div>
<button type="button" class="block w-full min-h-[220px] text-left rounded-2xl bg-white/[0.04] border border-thv13-teal/30 shadow-[0_4px_20px_rgba(0,0,0,.4)] cursor-pointer transition-[transform,box-shadow] duration-400 ease-[cubic-bezier(.4,0,.2,1)] hover:-translate-y-[14px] hover:shadow-[0_28px_60px_rgba(0,0,0,.5),0_0_30px_rgba(20,184,166,.2)] focus-visible:-translate-y-[14px] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv13-teal motion-reduce:transition-none motion-reduce:hover:translate-y-0">
<span class="flex flex-col gap-3 p-8">
<span class="text-3xl text-thv13-teal">▲</span>
<span class="text-lg font-bold text-thv13-text">Float Lift</span>
<span class="text-sm leading-relaxed text-thv13-dim">translateY plus a longer cast shadow.</span>
</span>
</button>
</div>
<div class="perspective-[800px]">
<button type="button" class="group relative block w-full min-h-[220px] text-left rounded-2xl bg-white/[0.04] border border-thv13-sky/30 transform-3d cursor-pointer transition-transform duration-400 ease-[cubic-bezier(.4,0,.2,1)] hover:rotate-x-[6deg] hover:rotate-y-[-6deg] focus-visible:rotate-x-[6deg] focus-visible:rotate-y-[-6deg] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv13-sky motion-reduce:transition-none motion-reduce:hover:rotate-x-0 motion-reduce:hover:rotate-y-0">
<span class="absolute inset-0 rounded-2xl bg-[linear-gradient(135deg,rgba(14,165,233,.1),rgba(56,189,248,.05))]"></span>
<span class="absolute inset-0 flex items-start p-8 transition-transform duration-400 ease-[cubic-bezier(.4,0,.2,1)] group-hover:translate-z-[20px] group-hover:-translate-y-1.5 group-focus-visible:translate-z-[20px]"><span class="text-4xl text-thv13-sky">◉</span></span>
<span class="absolute inset-0 flex flex-col justify-end gap-2 p-7 transition-transform duration-400 ease-[cubic-bezier(.4,0,.2,1)] group-hover:translate-z-[35px] group-hover:-translate-y-1 group-focus-visible:translate-z-[35px]">
<span class="text-lg font-bold text-thv13-text">Parallax</span>
<span class="text-sm leading-relaxed text-thv13-dim">translateZ layered depth.</span>
</span>
</button>
</div>
</div>
</section>@import "tailwindcss";
@theme {
--color-thv13-bg: #020810;
--color-thv13-bg: oklch(0.12 0.02 250);
--color-thv13-text: #bae6fd;
--color-thv13-text: oklch(0.89 0.07 225);
--color-thv13-dim: #64748b;
--color-thv13-dim: oklch(0.55 0.03 257);
--color-thv13-blue: #0ea5e9;
--color-thv13-blue: oklch(0.7 0.15 233);
--color-thv13-sky: #38bdf8;
--color-thv13-sky: oklch(0.76 0.13 226);
--color-thv13-indigo: #6366f1;
--color-thv13-indigo: oklch(0.6 0.2 277);
--color-thv13-teal: #14b8a6;
--color-thv13-teal: oklch(0.72 0.13 180);
--font-thv13-sans: 'Space Grotesk', system-ui, sans-serif;
}
.thv-13 {
width: 100%;
min-height: 100svh;
}
.thv-13 ::selection {
background: var(--color-thv13-blue);
color: #fff;
}@import "tailwindcss";
@theme {
--color-thv13-bg: #020810;
--color-thv13-bg: oklch(0.12 0.02 250);
--color-thv13-text: #bae6fd;
--color-thv13-text: oklch(0.89 0.07 225);
--color-thv13-dim: #64748b;
--color-thv13-dim: oklch(0.55 0.03 257);
--color-thv13-blue: #0ea5e9;
--color-thv13-blue: oklch(0.7 0.15 233);
--color-thv13-sky: #38bdf8;
--color-thv13-sky: oklch(0.76 0.13 226);
--color-thv13-indigo: #6366f1;
--color-thv13-indigo: oklch(0.6 0.2 277);
--color-thv13-teal: #14b8a6;
--color-thv13-teal: oklch(0.72 0.13 180);
--font-thv13-sans: 'Space Grotesk', system-ui, sans-serif;
}
.thv-13 {
width: 100%;
min-height: 100svh;
}
.thv-13 ::selection {
background: var(--color-thv13-blue);
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-thv13-bg: #020810;
--color-thv13-bg: oklch(0.12 0.02 250);
--color-thv13-text: #bae6fd;
--color-thv13-text: oklch(0.89 0.07 225);
--color-thv13-dim: #64748b;
--color-thv13-dim: oklch(0.55 0.03 257);
--color-thv13-blue: #0ea5e9;
--color-thv13-blue: oklch(0.7 0.15 233);
--color-thv13-sky: #38bdf8;
--color-thv13-sky: oklch(0.76 0.13 226);
--color-thv13-indigo: #6366f1;
--color-thv13-indigo: oklch(0.6 0.2 277);
--color-thv13-teal: #14b8a6;
--color-thv13-teal: oklch(0.72 0.13 180);
--font-thv13-sans: 'Space Grotesk', system-ui, sans-serif;
}
.thv-13 {
width: 100%;
min-height: 100svh;
}
.thv-13 ::selection {
background: var(--color-thv13-blue);
color: #fff;
}@import "tailwindcss";
@theme {
--color-thv13-bg: #020810;
--color-thv13-bg: oklch(0.12 0.02 250);
--color-thv13-text: #bae6fd;
--color-thv13-text: oklch(0.89 0.07 225);
--color-thv13-dim: #64748b;
--color-thv13-dim: oklch(0.55 0.03 257);
--color-thv13-blue: #0ea5e9;
--color-thv13-blue: oklch(0.7 0.15 233);
--color-thv13-sky: #38bdf8;
--color-thv13-sky: oklch(0.76 0.13 226);
--color-thv13-indigo: #6366f1;
--color-thv13-indigo: oklch(0.6 0.2 277);
--color-thv13-teal: #14b8a6;
--color-thv13-teal: oklch(0.72 0.13 180);
--font-thv13-sans: 'Space Grotesk', system-ui, sans-serif;
}
.thv-13 {
width: 100%;
min-height: 100svh;
}
.thv-13 ::selection {
background: var(--color-thv13-blue);
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.
- v4's 3D utilities (
perspective-*,transform-3d,rotate-x-*,translate-z-*) mean this demo ports almost one-for-one, with the element roles now readable in the markup. - UI change from the CSS original: the cards were hover-only
<div>s; they are now buttons with tab stops, focus rings andgroup-focus-visible:parallax. - Under
motion-reduce:the tilts resolve to a border-colour change rather than nothing, so the hover is still legible without vestibular motion.
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 3D Tilt Card Hover Effect
Source: https://codefronts.com/motion/tailwind-css-hover-effects/tailwind-3d-tilt-card-hover-effect/
Four perspective cards — fixed diagonal tilt, opposite-axis tilt, a float lift with shadow depth, and translateZ parallax layers. v4 ships perspective-*, transform-3d, rotate-x-* and translate-z-*, so this port needs almost no arbitrary values.
## HTML
```html
<section class="thv-13 w-full min-h-svh grid place-items-center bg-thv13-bg font-thv13-sans px-6 py-14">
<div class="w-[min(800px,100%)] grid grid-cols-[repeat(auto-fit,minmax(280px,1fr))] gap-10">
<div class="perspective-[800px]">
<button type="button" class="block w-full min-h-[220px] text-left rounded-2xl bg-white/[0.04] border border-white/10 transform-3d cursor-pointer transition-[transform,box-shadow] duration-400 ease-[cubic-bezier(.4,0,.2,1)] hover:rotate-x-[8deg] hover:rotate-y-[-8deg] hover:shadow-[8px_12px_40px_rgba(14,165,233,.3)] focus-visible:rotate-x-[8deg] focus-visible:rotate-y-[-8deg] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv13-blue motion-reduce:transition-none motion-reduce:hover:rotate-x-0 motion-reduce:hover:rotate-y-0 motion-reduce:hover:border-thv13-blue">
<span class="flex flex-col gap-3 p-8">
<span class="text-3xl text-thv13-blue">◈</span>
<span class="text-lg font-bold text-thv13-text">Static Tilt</span>
<span class="text-sm leading-relaxed text-thv13-dim">Perspective rotateX + rotateY on hover.</span>
</span>
</button>
</div>
<div class="perspective-[800px]">
<button type="button" class="block w-full min-h-[220px] text-left rounded-2xl bg-white/[0.04] border border-thv13-indigo/30 transform-3d cursor-pointer transition-[transform,box-shadow,border-color] duration-400 ease-[cubic-bezier(.4,0,.2,1)] hover:rotate-x-[-6deg] hover:rotate-y-[10deg] hover:border-thv13-indigo/60 hover:shadow-[-10px_8px_40px_rgba(99,102,241,.3)] focus-visible:rotate-x-[-6deg] focus-visible:rotate-y-[10deg] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv13-indigo motion-reduce:transition-none motion-reduce:hover:rotate-x-0 motion-reduce:hover:rotate-y-0">
<span class="flex flex-col gap-3 p-8">
<span class="text-3xl text-thv13-indigo">⬡</span>
<span class="text-lg font-bold text-thv13-text">Axis Flip</span>
<span class="text-sm leading-relaxed text-thv13-dim">Opposite-axis lean with a matching cast shadow.</span>
</span>
</button>
</div>
<div>
<button type="button" class="block w-full min-h-[220px] text-left rounded-2xl bg-white/[0.04] border border-thv13-teal/30 shadow-[0_4px_20px_rgba(0,0,0,.4)] cursor-pointer transition-[transform,box-shadow] duration-400 ease-[cubic-bezier(.4,0,.2,1)] hover:-translate-y-[14px] hover:shadow-[0_28px_60px_rgba(0,0,0,.5),0_0_30px_rgba(20,184,166,.2)] focus-visible:-translate-y-[14px] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv13-teal motion-reduce:transition-none motion-reduce:hover:translate-y-0">
<span class="flex flex-col gap-3 p-8">
<span class="text-3xl text-thv13-teal">▲</span>
<span class="text-lg font-bold text-thv13-text">Float Lift</span>
<span class="text-sm leading-relaxed text-thv13-dim">translateY plus a longer cast shadow.</span>
</span>
</button>
</div>
<div class="perspective-[800px]">
<button type="button" class="group relative block w-full min-h-[220px] text-left rounded-2xl bg-white/[0.04] border border-thv13-sky/30 transform-3d cursor-pointer transition-transform duration-400 ease-[cubic-bezier(.4,0,.2,1)] hover:rotate-x-[6deg] hover:rotate-y-[-6deg] focus-visible:rotate-x-[6deg] focus-visible:rotate-y-[-6deg] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv13-sky motion-reduce:transition-none motion-reduce:hover:rotate-x-0 motion-reduce:hover:rotate-y-0">
<span class="absolute inset-0 rounded-2xl bg-[linear-gradient(135deg,rgba(14,165,233,.1),rgba(56,189,248,.05))]"></span>
<span class="absolute inset-0 flex items-start p-8 transition-transform duration-400 ease-[cubic-bezier(.4,0,.2,1)] group-hover:translate-z-[20px] group-hover:-translate-y-1.5 group-focus-visible:translate-z-[20px]"><span class="text-4xl text-thv13-sky">◉</span></span>
<span class="absolute inset-0 flex flex-col justify-end gap-2 p-7 transition-transform duration-400 ease-[cubic-bezier(.4,0,.2,1)] group-hover:translate-z-[35px] group-hover:-translate-y-1 group-focus-visible:translate-z-[35px]">
<span class="text-lg font-bold text-thv13-text">Parallax</span>
<span class="text-sm leading-relaxed text-thv13-dim">translateZ layered depth.</span>
</span>
</button>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-thv13-bg: #020810;
--color-thv13-bg: oklch(0.12 0.02 250);
--color-thv13-text: #bae6fd;
--color-thv13-text: oklch(0.89 0.07 225);
--color-thv13-dim: #64748b;
--color-thv13-dim: oklch(0.55 0.03 257);
--color-thv13-blue: #0ea5e9;
--color-thv13-blue: oklch(0.7 0.15 233);
--color-thv13-sky: #38bdf8;
--color-thv13-sky: oklch(0.76 0.13 226);
--color-thv13-indigo: #6366f1;
--color-thv13-indigo: oklch(0.6 0.2 277);
--color-thv13-teal: #14b8a6;
--color-thv13-teal: oklch(0.72 0.13 180);
--font-thv13-sans: 'Space Grotesk', system-ui, sans-serif;
}
.thv-13 {
width: 100%;
min-height: 100svh;
}
.thv-13 ::selection {
background: var(--color-thv13-blue);
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 3D Tilt Card Hover Effect
Source: https://codefronts.com/motion/tailwind-css-hover-effects/tailwind-3d-tilt-card-hover-effect/
Four perspective cards — fixed diagonal tilt, opposite-axis tilt, a float lift with shadow depth, and translateZ parallax layers. v4 ships perspective-*, transform-3d, rotate-x-* and translate-z-*, so this port needs almost no arbitrary values.
## HTML
```html
<section class="thv-13 w-full min-h-svh grid place-items-center bg-thv13-bg font-thv13-sans px-6 py-14">
<div class="w-[min(800px,100%)] grid grid-cols-[repeat(auto-fit,minmax(280px,1fr))] gap-10">
<div class="perspective-[800px]">
<button type="button" class="block w-full min-h-[220px] text-left rounded-2xl bg-white/[0.04] border border-white/10 transform-3d cursor-pointer transition-[transform,box-shadow] duration-400 ease-[cubic-bezier(.4,0,.2,1)] hover:rotate-x-[8deg] hover:rotate-y-[-8deg] hover:shadow-[8px_12px_40px_rgba(14,165,233,.3)] focus-visible:rotate-x-[8deg] focus-visible:rotate-y-[-8deg] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv13-blue motion-reduce:transition-none motion-reduce:hover:rotate-x-0 motion-reduce:hover:rotate-y-0 motion-reduce:hover:border-thv13-blue">
<span class="flex flex-col gap-3 p-8">
<span class="text-3xl text-thv13-blue">◈</span>
<span class="text-lg font-bold text-thv13-text">Static Tilt</span>
<span class="text-sm leading-relaxed text-thv13-dim">Perspective rotateX + rotateY on hover.</span>
</span>
</button>
</div>
<div class="perspective-[800px]">
<button type="button" class="block w-full min-h-[220px] text-left rounded-2xl bg-white/[0.04] border border-thv13-indigo/30 transform-3d cursor-pointer transition-[transform,box-shadow,border-color] duration-400 ease-[cubic-bezier(.4,0,.2,1)] hover:rotate-x-[-6deg] hover:rotate-y-[10deg] hover:border-thv13-indigo/60 hover:shadow-[-10px_8px_40px_rgba(99,102,241,.3)] focus-visible:rotate-x-[-6deg] focus-visible:rotate-y-[10deg] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv13-indigo motion-reduce:transition-none motion-reduce:hover:rotate-x-0 motion-reduce:hover:rotate-y-0">
<span class="flex flex-col gap-3 p-8">
<span class="text-3xl text-thv13-indigo">⬡</span>
<span class="text-lg font-bold text-thv13-text">Axis Flip</span>
<span class="text-sm leading-relaxed text-thv13-dim">Opposite-axis lean with a matching cast shadow.</span>
</span>
</button>
</div>
<div>
<button type="button" class="block w-full min-h-[220px] text-left rounded-2xl bg-white/[0.04] border border-thv13-teal/30 shadow-[0_4px_20px_rgba(0,0,0,.4)] cursor-pointer transition-[transform,box-shadow] duration-400 ease-[cubic-bezier(.4,0,.2,1)] hover:-translate-y-[14px] hover:shadow-[0_28px_60px_rgba(0,0,0,.5),0_0_30px_rgba(20,184,166,.2)] focus-visible:-translate-y-[14px] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv13-teal motion-reduce:transition-none motion-reduce:hover:translate-y-0">
<span class="flex flex-col gap-3 p-8">
<span class="text-3xl text-thv13-teal">▲</span>
<span class="text-lg font-bold text-thv13-text">Float Lift</span>
<span class="text-sm leading-relaxed text-thv13-dim">translateY plus a longer cast shadow.</span>
</span>
</button>
</div>
<div class="perspective-[800px]">
<button type="button" class="group relative block w-full min-h-[220px] text-left rounded-2xl bg-white/[0.04] border border-thv13-sky/30 transform-3d cursor-pointer transition-transform duration-400 ease-[cubic-bezier(.4,0,.2,1)] hover:rotate-x-[6deg] hover:rotate-y-[-6deg] focus-visible:rotate-x-[6deg] focus-visible:rotate-y-[-6deg] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-thv13-sky motion-reduce:transition-none motion-reduce:hover:rotate-x-0 motion-reduce:hover:rotate-y-0">
<span class="absolute inset-0 rounded-2xl bg-[linear-gradient(135deg,rgba(14,165,233,.1),rgba(56,189,248,.05))]"></span>
<span class="absolute inset-0 flex items-start p-8 transition-transform duration-400 ease-[cubic-bezier(.4,0,.2,1)] group-hover:translate-z-[20px] group-hover:-translate-y-1.5 group-focus-visible:translate-z-[20px]"><span class="text-4xl text-thv13-sky">◉</span></span>
<span class="absolute inset-0 flex flex-col justify-end gap-2 p-7 transition-transform duration-400 ease-[cubic-bezier(.4,0,.2,1)] group-hover:translate-z-[35px] group-hover:-translate-y-1 group-focus-visible:translate-z-[35px]">
<span class="text-lg font-bold text-thv13-text">Parallax</span>
<span class="text-sm leading-relaxed text-thv13-dim">translateZ layered depth.</span>
</span>
</button>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-thv13-bg: #020810;
--color-thv13-bg: oklch(0.12 0.02 250);
--color-thv13-text: #bae6fd;
--color-thv13-text: oklch(0.89 0.07 225);
--color-thv13-dim: #64748b;
--color-thv13-dim: oklch(0.55 0.03 257);
--color-thv13-blue: #0ea5e9;
--color-thv13-blue: oklch(0.7 0.15 233);
--color-thv13-sky: #38bdf8;
--color-thv13-sky: oklch(0.76 0.13 226);
--color-thv13-indigo: #6366f1;
--color-thv13-indigo: oklch(0.6 0.2 277);
--color-thv13-teal: #14b8a6;
--color-thv13-teal: oklch(0.72 0.13 180);
--font-thv13-sans: 'Space Grotesk', system-ui, sans-serif;
}
.thv-13 {
width: 100%;
min-height: 100svh;
}
.thv-13 ::selection {
background: var(--color-thv13-blue);
color: #fff;
}
```How this works
Three elements, three jobs. The scene holds perspective-[800px], the card holds transform-3d and the rotation, and the layers hold their own translate-z. Tailwind names all three, so the arrangement is legible from the markup alone — the usual failure mode (perspective on the wrong element) becomes visible.
Lift is not tilt. The float card never rotates: hover:-translate-y-[14px] paired with a much larger shadow does the work, because a rising object casts a longer shadow.
Parallax is per-layer. group-hover:translate-z-[20px] on the middle layer and [35px] on the top makes the content separate as the card turns.
Make it yours
- Tilt strength:
rotate-x-[8deg]→[14deg]; past 20deg the text stops reading. - Perspective distance:
perspective-[600px]for fish-eye,[1200px]for a near-flat lean. - Asymmetric feel:
duration-100on hover-in with a longer default duration for the return.
Gotchas — read before shipping
overflow-hiddenflattens atransform-3dsubtree — the parallax card deliberately has none.- Promoting the card with
will-changecreates a stacking context that can reorder it against siblings; leave it off unless you measure jank. - Rounded corners plus 3D rotation render imprecisely in some Safari versions — keep radii on the faces, not on a transformed ancestor.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
3D transforms are Baseline; perspective-* and transform-3d are v4 core utilities.