06 / 36
All 36 in 36 Tailwind CSS Button Hover Effects
- 01Tailwind Magnetic Ripple Attraction Button Hover Effect
- 02Tailwind Cyberpunk Holographic Glitch Grid Button
- 03Tailwind Frosted Glassmorphism Shimmer Glow Button
- 04Tailwind Organic Blob Morph Button Hover Effect
- 05Tailwind Dual-Line Intersection Border Draw Button
- 06Tailwind Isometric Tactile 3D Depress Button
- 07Tailwind Infinite Sliding Kinetic Marquee Button
- 08Tailwind Chroma Conic Gradient Border Spin Button
- 09Tailwind Minimalist Border & Outline Drawing Hover Effects
- 10Tailwind Modern 3D Skeuomorphic Button Press Effects
- 11Tailwind Neo-Brutalist & Cyberpunk Button Glow Effects
- 12Tailwind Sliding Background Color Wipe Button Effects
- 13Tailwind Liquid Fill & Organic Morphing Button Effects
- 14Tailwind Kinetic Text Flip & Icon Reveal Button Effects
- 15Tailwind Liquid Wave Fill Button Hover Effect
- 16Tailwind Magnetic Border Drift Button
- 17Tailwind Glitch Slice Button Hover Effect
- 18Tailwind Neon Pulse Glow Button Hover Effect
- 19Tailwind Split Reveal Curtain Button Effect
- 20Tailwind Diagonal Shutter Sweep Button Effect
- 21Tailwind Elastic Lift Spring Button Hover Effect
- 22Tailwind Center Underline Draw Link Button Effects
- 23Tailwind 3D Flip Card Button Hover Effect
- 24Tailwind Particle Burst Confetti Button Effect
- 25Tailwind Slide Doors Closing Panel Button Effect
- 26Tailwind Typewriter Retype Terminal Button Effect
- 27Tailwind Hard Shadow Shift Flat Button Effect
- 28Tailwind Material Ripple Wave Button Effect
- 29Tailwind Rainbow Gradient Border Spin Button
- 30Tailwind Morph Shape Silhouette Button Effects
- 31Tailwind Icon Slide In Directional Button Effect
- 32Tailwind Cursor Spotlight Glow Button
- 33Tailwind Stagger Fill Equaliser Button Effect
- 34Tailwind Sunburst Expand Radiant Button Effect
- 35Tailwind 3D Press Plunger Key Button Effect
- 36Tailwind Add-to-Cart Liquid Glass Ripple Button
Tailwind Isometric Tactile 3D Depress Button
A chunky game-UI button in isometric perspective with a thick extruded side, so it looks like a real key. On hover the tilt eases toward flat and the shadow stack collapses; on press it lands. This is the batch's best illustration of v4's discrete rotate property — three states, and not one of them restates the others.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<div class="tbh-06-group w-full min-h-svh flex flex-wrap">
<section class="tbh-06a flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-[70px] font-tbh06-sans bg-tbh06a-stage [perspective:700px]" aria-label="Isometric 3D button">
<button type="button" class="cursor-pointer border-0 rounded-2xl px-10 py-[18px] text-[18px] font-extrabold text-tbh06a-ink bg-tbh06a-cap [rotate:x_15deg] -translate-y-1.5 shadow-[0_1px_0_var(--color-tbh06a-side),0_2px_0_var(--color-tbh06a-side),0_3px_0_var(--color-tbh06a-side),0_4px_0_var(--color-tbh06a-side),0_5px_0_var(--color-tbh06a-side),0_6px_0_var(--color-tbh06a-side),0_7px_0_var(--color-tbh06a-side),0_8px_0_var(--color-tbh06a-side),0_20px_24px_-8px_oklch(0_0_0/0.45)] transition-[rotate,translate,box-shadow] duration-[220ms] ease-[cubic-bezier(.3,.7,.4,1)] hover:[rotate:x_4deg] hover:-translate-y-px hover:shadow-[0_1px_0_var(--color-tbh06a-side),0_2px_0_var(--color-tbh06a-side),0_3px_0_var(--color-tbh06a-side),0_4px_0_var(--color-tbh06a-side),0_12px_16px_-8px_oklch(0_0_0/0.4)] focus-visible:[rotate:x_4deg] focus-visible:-translate-y-px active:[rotate:x_0deg] active:translate-y-0.5 active:shadow-[0_1px_0_var(--color-tbh06a-side),0_2px_0_var(--color-tbh06a-side),0_6px_10px_-6px_oklch(0_0_0/0.4)] focus-visible:outline-3 focus-visible:outline-tbh06a-ink focus-visible:outline-offset-4 motion-reduce:transition-[box-shadow] motion-reduce:duration-150">
Press me
</button>
</section>
<section class="tbh-06b flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh06-sans bg-tbh06b-stage" aria-label="Pushable 3D pill button">
<button type="button" class="group/btn relative cursor-pointer border-0 bg-transparent p-0 rounded-[14px] text-[17px] font-extrabold text-white focus-visible:outline-3 focus-visible:outline-white focus-visible:outline-offset-4">
<span aria-hidden="true" class="absolute inset-0 rounded-[14px] bg-tbh06b-edge"></span>
<span class="block relative px-10 py-4 rounded-[14px] bg-tbh06b-front -translate-y-1.5 transition-[translate] duration-[120ms] ease-[cubic-bezier(.3,.7,.4,1)] group-hover/btn:-translate-y-2 group-focus-visible/btn:-translate-y-2 group-active/btn:-translate-y-px motion-reduce:duration-[100ms]">Buy now</span>
</button>
</section>
</div><div class="tbh-06-group w-full min-h-svh flex flex-wrap">
<section class="tbh-06a flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-[70px] font-tbh06-sans bg-tbh06a-stage [perspective:700px]" aria-label="Isometric 3D button">
<button type="button" class="cursor-pointer border-0 rounded-2xl px-10 py-[18px] text-[18px] font-extrabold text-tbh06a-ink bg-tbh06a-cap [rotate:x_15deg] -translate-y-1.5 shadow-[0_1px_0_var(--color-tbh06a-side),0_2px_0_var(--color-tbh06a-side),0_3px_0_var(--color-tbh06a-side),0_4px_0_var(--color-tbh06a-side),0_5px_0_var(--color-tbh06a-side),0_6px_0_var(--color-tbh06a-side),0_7px_0_var(--color-tbh06a-side),0_8px_0_var(--color-tbh06a-side),0_20px_24px_-8px_oklch(0_0_0/0.45)] transition-[rotate,translate,box-shadow] duration-[220ms] ease-[cubic-bezier(.3,.7,.4,1)] hover:[rotate:x_4deg] hover:-translate-y-px hover:shadow-[0_1px_0_var(--color-tbh06a-side),0_2px_0_var(--color-tbh06a-side),0_3px_0_var(--color-tbh06a-side),0_4px_0_var(--color-tbh06a-side),0_12px_16px_-8px_oklch(0_0_0/0.4)] focus-visible:[rotate:x_4deg] focus-visible:-translate-y-px active:[rotate:x_0deg] active:translate-y-0.5 active:shadow-[0_1px_0_var(--color-tbh06a-side),0_2px_0_var(--color-tbh06a-side),0_6px_10px_-6px_oklch(0_0_0/0.4)] focus-visible:outline-3 focus-visible:outline-tbh06a-ink focus-visible:outline-offset-4 motion-reduce:transition-[box-shadow] motion-reduce:duration-150">
Press me
</button>
</section>
<section class="tbh-06b flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh06-sans bg-tbh06b-stage" aria-label="Pushable 3D pill button">
<button type="button" class="group/btn relative cursor-pointer border-0 bg-transparent p-0 rounded-[14px] text-[17px] font-extrabold text-white focus-visible:outline-3 focus-visible:outline-white focus-visible:outline-offset-4">
<span aria-hidden="true" class="absolute inset-0 rounded-[14px] bg-tbh06b-edge"></span>
<span class="block relative px-10 py-4 rounded-[14px] bg-tbh06b-front -translate-y-1.5 transition-[translate] duration-[120ms] ease-[cubic-bezier(.3,.7,.4,1)] group-hover/btn:-translate-y-2 group-focus-visible/btn:-translate-y-2 group-active/btn:-translate-y-px motion-reduce:duration-[100ms]">Buy now</span>
</button>
</section>
</div>@import "tailwindcss";
@theme {
--color-tbh06a-cap: #5ed39a;
--color-tbh06a-cap: oklch(0.72 0.16 155);
--color-tbh06a-side: #2e8f63;
--color-tbh06a-side: oklch(0.5 0.13 155);
--color-tbh06a-ink: #08351f;
--color-tbh06a-ink: oklch(0.3 0.08 160);
--color-tbh06a-stage: #eef6f1;
--color-tbh06a-stage: oklch(0.96 0.015 160);
--color-tbh06b-front: #ef8a4a;
--color-tbh06b-front: oklch(0.68 0.18 40);
--color-tbh06b-edge: #9c5122;
--color-tbh06b-edge: oklch(0.42 0.14 40);
--color-tbh06b-stage: #1a120c;
--color-tbh06b-stage: oklch(0.2 0.03 50);
--font-tbh06-sans: 'Space Grotesk', system-ui, sans-serif;
}
/* Nothing needs to stay CSS here: perspective, rotate and the shadow stacks are all
expressible as utilities or arbitrary properties. */
.tbh-06-group {
width: 100%;
min-height: 100svh;
}
.tbh-06a,
.tbh-06b {
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tbh06a-cap: #5ed39a;
--color-tbh06a-cap: oklch(0.72 0.16 155);
--color-tbh06a-side: #2e8f63;
--color-tbh06a-side: oklch(0.5 0.13 155);
--color-tbh06a-ink: #08351f;
--color-tbh06a-ink: oklch(0.3 0.08 160);
--color-tbh06a-stage: #eef6f1;
--color-tbh06a-stage: oklch(0.96 0.015 160);
--color-tbh06b-front: #ef8a4a;
--color-tbh06b-front: oklch(0.68 0.18 40);
--color-tbh06b-edge: #9c5122;
--color-tbh06b-edge: oklch(0.42 0.14 40);
--color-tbh06b-stage: #1a120c;
--color-tbh06b-stage: oklch(0.2 0.03 50);
--font-tbh06-sans: 'Space Grotesk', system-ui, sans-serif;
}
/* Nothing needs to stay CSS here: perspective, rotate and the shadow stacks are all
expressible as utilities or arbitrary properties. */
.tbh-06-group {
width: 100%;
min-height: 100svh;
}
.tbh-06a,
.tbh-06b {
min-height: 100svh;
}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-tbh06a-cap: #5ed39a;
--color-tbh06a-cap: oklch(0.72 0.16 155);
--color-tbh06a-side: #2e8f63;
--color-tbh06a-side: oklch(0.5 0.13 155);
--color-tbh06a-ink: #08351f;
--color-tbh06a-ink: oklch(0.3 0.08 160);
--color-tbh06a-stage: #eef6f1;
--color-tbh06a-stage: oklch(0.96 0.015 160);
--color-tbh06b-front: #ef8a4a;
--color-tbh06b-front: oklch(0.68 0.18 40);
--color-tbh06b-edge: #9c5122;
--color-tbh06b-edge: oklch(0.42 0.14 40);
--color-tbh06b-stage: #1a120c;
--color-tbh06b-stage: oklch(0.2 0.03 50);
--font-tbh06-sans: 'Space Grotesk', system-ui, sans-serif;
}
/* Nothing needs to stay CSS here: perspective, rotate and the shadow stacks are all
expressible as utilities or arbitrary properties. */
.tbh-06-group {
width: 100%;
min-height: 100svh;
}
.tbh-06a,
.tbh-06b {
min-height: 100svh;
}@import "tailwindcss";
@theme {
--color-tbh06a-cap: #5ed39a;
--color-tbh06a-cap: oklch(0.72 0.16 155);
--color-tbh06a-side: #2e8f63;
--color-tbh06a-side: oklch(0.5 0.13 155);
--color-tbh06a-ink: #08351f;
--color-tbh06a-ink: oklch(0.3 0.08 160);
--color-tbh06a-stage: #eef6f1;
--color-tbh06a-stage: oklch(0.96 0.015 160);
--color-tbh06b-front: #ef8a4a;
--color-tbh06b-front: oklch(0.68 0.18 40);
--color-tbh06b-edge: #9c5122;
--color-tbh06b-edge: oklch(0.42 0.14 40);
--color-tbh06b-stage: #1a120c;
--color-tbh06b-stage: oklch(0.2 0.03 50);
--font-tbh06-sans: 'Space Grotesk', system-ui, sans-serif;
}
/* Nothing needs to stay CSS here: perspective, rotate and the shadow stacks are all
expressible as utilities or arbitrary properties. */
.tbh-06-group {
width: 100%;
min-height: 100svh;
}
.tbh-06a,
.tbh-06b {
min-height: 100svh;
}<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&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&display=swap">What changed in the port
Which parts became utilities, which stayed CSS, and why.
- The clearest win in the collection for v4's discrete transform properties. Three compound
transformdeclarations holding nine coupled numbers become three states that each name one property — and the eight-layer shadow, the only genuinely verbose part, is verbose in CSS too. [rotate:x_15deg]rather thanrotate-x-15is deliberate: the arbitrary property form is stable across v4 point releases and states plainly that this is a scene angle, not a scale step.- UI change from the CSS original: design A's hover tilt is mirrored on
focus-visible:, design B's lift likewise, and design A gained a light stage (the original left it transparent, so the drop shadow had nothing to fall on).
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 Isometric Tactile 3D Depress Button
Source: https://codefronts.com/motion/tailwind-css-button-hover-effects/tailwind-isometric-tactile-3d-depress-button/
A chunky game-UI button in isometric perspective with a thick extruded side, so it looks like a real key. On hover the tilt eases toward flat and the shadow stack collapses; on press it lands. This is the batch's best illustration of v4's discrete rotate property — three states, and not one of them restates the others.
## HTML
```html
<div class="tbh-06-group w-full min-h-svh flex flex-wrap">
<section class="tbh-06a flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-[70px] font-tbh06-sans bg-tbh06a-stage [perspective:700px]" aria-label="Isometric 3D button">
<button type="button" class="cursor-pointer border-0 rounded-2xl px-10 py-[18px] text-[18px] font-extrabold text-tbh06a-ink bg-tbh06a-cap [rotate:x_15deg] -translate-y-1.5 shadow-[0_1px_0_var(--color-tbh06a-side),0_2px_0_var(--color-tbh06a-side),0_3px_0_var(--color-tbh06a-side),0_4px_0_var(--color-tbh06a-side),0_5px_0_var(--color-tbh06a-side),0_6px_0_var(--color-tbh06a-side),0_7px_0_var(--color-tbh06a-side),0_8px_0_var(--color-tbh06a-side),0_20px_24px_-8px_oklch(0_0_0/0.45)] transition-[rotate,translate,box-shadow] duration-[220ms] ease-[cubic-bezier(.3,.7,.4,1)] hover:[rotate:x_4deg] hover:-translate-y-px hover:shadow-[0_1px_0_var(--color-tbh06a-side),0_2px_0_var(--color-tbh06a-side),0_3px_0_var(--color-tbh06a-side),0_4px_0_var(--color-tbh06a-side),0_12px_16px_-8px_oklch(0_0_0/0.4)] focus-visible:[rotate:x_4deg] focus-visible:-translate-y-px active:[rotate:x_0deg] active:translate-y-0.5 active:shadow-[0_1px_0_var(--color-tbh06a-side),0_2px_0_var(--color-tbh06a-side),0_6px_10px_-6px_oklch(0_0_0/0.4)] focus-visible:outline-3 focus-visible:outline-tbh06a-ink focus-visible:outline-offset-4 motion-reduce:transition-[box-shadow] motion-reduce:duration-150">
Press me
</button>
</section>
<section class="tbh-06b flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh06-sans bg-tbh06b-stage" aria-label="Pushable 3D pill button">
<button type="button" class="group/btn relative cursor-pointer border-0 bg-transparent p-0 rounded-[14px] text-[17px] font-extrabold text-white focus-visible:outline-3 focus-visible:outline-white focus-visible:outline-offset-4">
<span aria-hidden="true" class="absolute inset-0 rounded-[14px] bg-tbh06b-edge"></span>
<span class="block relative px-10 py-4 rounded-[14px] bg-tbh06b-front -translate-y-1.5 transition-[translate] duration-[120ms] ease-[cubic-bezier(.3,.7,.4,1)] group-hover/btn:-translate-y-2 group-focus-visible/btn:-translate-y-2 group-active/btn:-translate-y-px motion-reduce:duration-[100ms]">Buy now</span>
</button>
</section>
</div>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tbh06a-cap: #5ed39a;
--color-tbh06a-cap: oklch(0.72 0.16 155);
--color-tbh06a-side: #2e8f63;
--color-tbh06a-side: oklch(0.5 0.13 155);
--color-tbh06a-ink: #08351f;
--color-tbh06a-ink: oklch(0.3 0.08 160);
--color-tbh06a-stage: #eef6f1;
--color-tbh06a-stage: oklch(0.96 0.015 160);
--color-tbh06b-front: #ef8a4a;
--color-tbh06b-front: oklch(0.68 0.18 40);
--color-tbh06b-edge: #9c5122;
--color-tbh06b-edge: oklch(0.42 0.14 40);
--color-tbh06b-stage: #1a120c;
--color-tbh06b-stage: oklch(0.2 0.03 50);
--font-tbh06-sans: 'Space Grotesk', system-ui, sans-serif;
}
/* Nothing needs to stay CSS here: perspective, rotate and the shadow stacks are all
expressible as utilities or arbitrary properties. */
.tbh-06-group {
width: 100%;
min-height: 100svh;
}
.tbh-06a,
.tbh-06b {
min-height: 100svh;
}
```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 Isometric Tactile 3D Depress Button
Source: https://codefronts.com/motion/tailwind-css-button-hover-effects/tailwind-isometric-tactile-3d-depress-button/
A chunky game-UI button in isometric perspective with a thick extruded side, so it looks like a real key. On hover the tilt eases toward flat and the shadow stack collapses; on press it lands. This is the batch's best illustration of v4's discrete rotate property — three states, and not one of them restates the others.
## HTML
```html
<div class="tbh-06-group w-full min-h-svh flex flex-wrap">
<section class="tbh-06a flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-[70px] font-tbh06-sans bg-tbh06a-stage [perspective:700px]" aria-label="Isometric 3D button">
<button type="button" class="cursor-pointer border-0 rounded-2xl px-10 py-[18px] text-[18px] font-extrabold text-tbh06a-ink bg-tbh06a-cap [rotate:x_15deg] -translate-y-1.5 shadow-[0_1px_0_var(--color-tbh06a-side),0_2px_0_var(--color-tbh06a-side),0_3px_0_var(--color-tbh06a-side),0_4px_0_var(--color-tbh06a-side),0_5px_0_var(--color-tbh06a-side),0_6px_0_var(--color-tbh06a-side),0_7px_0_var(--color-tbh06a-side),0_8px_0_var(--color-tbh06a-side),0_20px_24px_-8px_oklch(0_0_0/0.45)] transition-[rotate,translate,box-shadow] duration-[220ms] ease-[cubic-bezier(.3,.7,.4,1)] hover:[rotate:x_4deg] hover:-translate-y-px hover:shadow-[0_1px_0_var(--color-tbh06a-side),0_2px_0_var(--color-tbh06a-side),0_3px_0_var(--color-tbh06a-side),0_4px_0_var(--color-tbh06a-side),0_12px_16px_-8px_oklch(0_0_0/0.4)] focus-visible:[rotate:x_4deg] focus-visible:-translate-y-px active:[rotate:x_0deg] active:translate-y-0.5 active:shadow-[0_1px_0_var(--color-tbh06a-side),0_2px_0_var(--color-tbh06a-side),0_6px_10px_-6px_oklch(0_0_0/0.4)] focus-visible:outline-3 focus-visible:outline-tbh06a-ink focus-visible:outline-offset-4 motion-reduce:transition-[box-shadow] motion-reduce:duration-150">
Press me
</button>
</section>
<section class="tbh-06b flex-[1_1_340px] min-w-[300px] grid place-items-center px-6 py-14 font-tbh06-sans bg-tbh06b-stage" aria-label="Pushable 3D pill button">
<button type="button" class="group/btn relative cursor-pointer border-0 bg-transparent p-0 rounded-[14px] text-[17px] font-extrabold text-white focus-visible:outline-3 focus-visible:outline-white focus-visible:outline-offset-4">
<span aria-hidden="true" class="absolute inset-0 rounded-[14px] bg-tbh06b-edge"></span>
<span class="block relative px-10 py-4 rounded-[14px] bg-tbh06b-front -translate-y-1.5 transition-[translate] duration-[120ms] ease-[cubic-bezier(.3,.7,.4,1)] group-hover/btn:-translate-y-2 group-focus-visible/btn:-translate-y-2 group-active/btn:-translate-y-px motion-reduce:duration-[100ms]">Buy now</span>
</button>
</section>
</div>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tbh06a-cap: #5ed39a;
--color-tbh06a-cap: oklch(0.72 0.16 155);
--color-tbh06a-side: #2e8f63;
--color-tbh06a-side: oklch(0.5 0.13 155);
--color-tbh06a-ink: #08351f;
--color-tbh06a-ink: oklch(0.3 0.08 160);
--color-tbh06a-stage: #eef6f1;
--color-tbh06a-stage: oklch(0.96 0.015 160);
--color-tbh06b-front: #ef8a4a;
--color-tbh06b-front: oklch(0.68 0.18 40);
--color-tbh06b-edge: #9c5122;
--color-tbh06b-edge: oklch(0.42 0.14 40);
--color-tbh06b-stage: #1a120c;
--color-tbh06b-stage: oklch(0.2 0.03 50);
--font-tbh06-sans: 'Space Grotesk', system-ui, sans-serif;
}
/* Nothing needs to stay CSS here: perspective, rotate and the shadow stacks are all
expressible as utilities or arbitrary properties. */
.tbh-06-group {
width: 100%;
min-height: 100svh;
}
.tbh-06a,
.tbh-06b {
min-height: 100svh;
}
```How this works
The extrusion is a shadow stack, not geometry. Eight zero-blur shadows at 1px increments read as a solid side wall, and shortening the stack on hover is what makes the cap look like it sank. Tailwind holds all three stacks in one class list, which is the first time this effect is readable without diffing three rules.
Tilt, lift and press stopped fighting. The CSS original wrote transform:rotateX(15deg) translateY(-6px), then had to repeat both values in :hover and again in :active — nine numbers to keep in sync. Here rotate and translate are separate properties, so each state names only what it changes.
Design B is the same idea with real layers. An absolute inset-0 edge in a darker tone, and a front face that translates up off it. Cheaper than the shadow stack, and the one to reach for when the button needs a border radius that reads cleanly at every state.
Make it yours
- Extrusion depth: add or remove
0_Npx_0layers in the resting shadow — and match the hover stack, or the cap appears to float. - Resting tilt:
[rotate:x_15deg]. Above ~20deg the label starts to distort. - Press feel:
duration-[220ms]withease-[cubic-bezier(.3,.7,.4,1)]; design B runs at 120ms because a shorter travel needs a shorter time. - Recolour cap and side independently through
--color-tbh06a-capand-side.
Gotchas — read before shipping
- Keep the side darker than the cap, or the extrusion reads as a glow rather than a wall.
[perspective:700px]belongs on the parent. On the button itself it applies to the button's own children and the tilt goes flat.- Match the hover
-translate-y-pxto the collapsed shadow depth — if the cap moves further than the wall shrinks, it detaches visually. - Design B's front face must carry the same radius as the edge beneath it, or a dark sliver shows at the corners.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
3D transforms, layered box-shadow and the discrete rotate property are all Baseline; no fallback needed beyond Tailwind v4's own floor.