10 / 20
All 20 in 20 Tailwind CSS Animated Buttons
- 01Tailwind Neon Glow Button with Pulsing Halo
- 02Tailwind Background Slide Hover Button (Four Directions)
- 03Tailwind Ripple Effect Button with No JavaScript
- 04Tailwind Animated Border Draw Button with Staged Delays
- 05Tailwind 3D Press Effect Button with Keycap Depth
- 06Tailwind Liquid Fill Button with Animated Wave Crest
- 07Tailwind Moving Gradient CTA Button
- 08Tailwind Shine Sweep Hover Button with Gloss Streak
- 09Tailwind Jelly Bounce Button with Elastic Squash
- 10Tailwind Text Flip Button Hover with 3D Rotation
- 11Tailwind Animated CTA Hero Button with Beacon Rings & Particle Burst
- 12Tailwind Submit Button Success State with Checkmark Draw
- 13Tailwind Animated Download Button with Progress Fill
- 14Tailwind Hamburger to Close Button with aria-expanded Variants
- 15Tailwind Add to Cart Button with Flying Product Dot
- 16Tailwind Social Share Buttons with Brand Hover & Copy Link
- 17Tailwind Animated Toggle Switch with peer-checked & has-checked
- 18Tailwind Loading Spinner Inside Button with State Machine
- 19Tailwind Next & Prev Arrow Buttons with Chasing Icons
- 20Tailwind Ghost Button with Cursor-Aware Background Reveal
Tailwind Text Flip Button Hover with 3D Rotation
The label pivots away on a horizontal axis and a second message pivots in behind it. The port's structural gain is group: the button declares it once and both panels read group-hover:, so the two halves of the flip are described on the elements that actually rotate.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tab-10 w-full min-h-svh grid place-items-center bg-tab10-bg font-tab10-sans px-6 py-10">
<div class="flex flex-col items-center gap-8">
<p class="text-[0.78rem] tracking-[0.14em] uppercase text-tab10-mut m-0">Hover to flip text</p>
<div class="flex flex-wrap justify-center gap-5">
<button type="button" class="group p-0 bg-tab10-indigo rounded-[10px] cursor-pointer perspective-[600px] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tab10-indigo">
<span class="relative block w-36 h-12 overflow-hidden transform-3d">
<span class="absolute inset-0 flex items-center justify-center text-[0.95rem] font-bold tracking-[0.04em] text-white whitespace-nowrap backface-hidden transition-transform duration-[350ms] ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:-translate-y-full group-hover:rotate-x-90 group-focus-visible:-translate-y-full group-focus-visible:rotate-x-90 motion-reduce:transition-opacity motion-reduce:group-hover:translate-y-0 motion-reduce:group-hover:rotate-x-0 motion-reduce:group-hover:opacity-0">View Pricing</span>
<span class="absolute inset-0 flex items-center justify-center text-[0.95rem] font-bold tracking-[0.04em] text-white whitespace-nowrap backface-hidden translate-y-full -rotate-x-90 transition-transform duration-[350ms] ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:translate-y-0 group-hover:rotate-x-0 group-focus-visible:translate-y-0 group-focus-visible:rotate-x-0 motion-reduce:translate-y-0 motion-reduce:rotate-x-0 motion-reduce:opacity-0 motion-reduce:transition-opacity motion-reduce:group-hover:opacity-100">From $9/mo →</span>
</span>
</button>
<button type="button" class="group p-0 bg-tab10-teal rounded-[10px] cursor-pointer perspective-[600px] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tab10-teal">
<span class="relative block w-36 h-12 overflow-hidden transform-3d">
<span class="absolute inset-0 flex items-center justify-center text-[0.95rem] font-bold tracking-[0.04em] text-white whitespace-nowrap backface-hidden transition-transform duration-[350ms] ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:-translate-y-full group-hover:rotate-x-90 group-focus-visible:-translate-y-full group-focus-visible:rotate-x-90 motion-reduce:transition-opacity motion-reduce:group-hover:translate-y-0 motion-reduce:group-hover:rotate-x-0 motion-reduce:group-hover:opacity-0">Follow Us</span>
<span class="absolute inset-0 flex items-center justify-center text-[0.95rem] font-bold tracking-[0.04em] text-white whitespace-nowrap backface-hidden translate-y-full -rotate-x-90 transition-transform duration-[350ms] ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:translate-y-0 group-hover:rotate-x-0 group-focus-visible:translate-y-0 group-focus-visible:rotate-x-0 motion-reduce:translate-y-0 motion-reduce:rotate-x-0 motion-reduce:opacity-0 motion-reduce:transition-opacity motion-reduce:group-hover:opacity-100">@codefronts</span>
</span>
</button>
<button type="button" class="group p-0 bg-tab10-rose rounded-[10px] cursor-pointer perspective-[600px] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tab10-rose">
<span class="relative block w-36 h-12 overflow-hidden transform-3d">
<span class="absolute inset-0 flex items-center justify-center text-[0.95rem] font-bold tracking-[0.04em] text-white whitespace-nowrap backface-hidden transition-transform duration-[350ms] ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:-translate-y-full group-hover:rotate-x-90 group-focus-visible:-translate-y-full group-focus-visible:rotate-x-90 motion-reduce:transition-opacity motion-reduce:group-hover:translate-y-0 motion-reduce:group-hover:rotate-x-0 motion-reduce:group-hover:opacity-0">Join Beta</span>
<span class="absolute inset-0 flex items-center justify-center text-[0.95rem] font-bold tracking-[0.04em] text-white whitespace-nowrap backface-hidden translate-y-full -rotate-x-90 transition-transform duration-[350ms] ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:translate-y-0 group-hover:rotate-x-0 group-focus-visible:translate-y-0 group-focus-visible:rotate-x-0 motion-reduce:translate-y-0 motion-reduce:rotate-x-0 motion-reduce:opacity-0 motion-reduce:transition-opacity motion-reduce:group-hover:opacity-100">Spots Left: 3</span>
</span>
</button>
</div>
</div>
</section><section class="tab-10 w-full min-h-svh grid place-items-center bg-tab10-bg font-tab10-sans px-6 py-10">
<div class="flex flex-col items-center gap-8">
<p class="text-[0.78rem] tracking-[0.14em] uppercase text-tab10-mut m-0">Hover to flip text</p>
<div class="flex flex-wrap justify-center gap-5">
<button type="button" class="group p-0 bg-tab10-indigo rounded-[10px] cursor-pointer perspective-[600px] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tab10-indigo">
<span class="relative block w-36 h-12 overflow-hidden transform-3d">
<span class="absolute inset-0 flex items-center justify-center text-[0.95rem] font-bold tracking-[0.04em] text-white whitespace-nowrap backface-hidden transition-transform duration-[350ms] ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:-translate-y-full group-hover:rotate-x-90 group-focus-visible:-translate-y-full group-focus-visible:rotate-x-90 motion-reduce:transition-opacity motion-reduce:group-hover:translate-y-0 motion-reduce:group-hover:rotate-x-0 motion-reduce:group-hover:opacity-0">View Pricing</span>
<span class="absolute inset-0 flex items-center justify-center text-[0.95rem] font-bold tracking-[0.04em] text-white whitespace-nowrap backface-hidden translate-y-full -rotate-x-90 transition-transform duration-[350ms] ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:translate-y-0 group-hover:rotate-x-0 group-focus-visible:translate-y-0 group-focus-visible:rotate-x-0 motion-reduce:translate-y-0 motion-reduce:rotate-x-0 motion-reduce:opacity-0 motion-reduce:transition-opacity motion-reduce:group-hover:opacity-100">From $9/mo →</span>
</span>
</button>
<button type="button" class="group p-0 bg-tab10-teal rounded-[10px] cursor-pointer perspective-[600px] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tab10-teal">
<span class="relative block w-36 h-12 overflow-hidden transform-3d">
<span class="absolute inset-0 flex items-center justify-center text-[0.95rem] font-bold tracking-[0.04em] text-white whitespace-nowrap backface-hidden transition-transform duration-[350ms] ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:-translate-y-full group-hover:rotate-x-90 group-focus-visible:-translate-y-full group-focus-visible:rotate-x-90 motion-reduce:transition-opacity motion-reduce:group-hover:translate-y-0 motion-reduce:group-hover:rotate-x-0 motion-reduce:group-hover:opacity-0">Follow Us</span>
<span class="absolute inset-0 flex items-center justify-center text-[0.95rem] font-bold tracking-[0.04em] text-white whitespace-nowrap backface-hidden translate-y-full -rotate-x-90 transition-transform duration-[350ms] ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:translate-y-0 group-hover:rotate-x-0 group-focus-visible:translate-y-0 group-focus-visible:rotate-x-0 motion-reduce:translate-y-0 motion-reduce:rotate-x-0 motion-reduce:opacity-0 motion-reduce:transition-opacity motion-reduce:group-hover:opacity-100">@codefronts</span>
</span>
</button>
<button type="button" class="group p-0 bg-tab10-rose rounded-[10px] cursor-pointer perspective-[600px] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tab10-rose">
<span class="relative block w-36 h-12 overflow-hidden transform-3d">
<span class="absolute inset-0 flex items-center justify-center text-[0.95rem] font-bold tracking-[0.04em] text-white whitespace-nowrap backface-hidden transition-transform duration-[350ms] ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:-translate-y-full group-hover:rotate-x-90 group-focus-visible:-translate-y-full group-focus-visible:rotate-x-90 motion-reduce:transition-opacity motion-reduce:group-hover:translate-y-0 motion-reduce:group-hover:rotate-x-0 motion-reduce:group-hover:opacity-0">Join Beta</span>
<span class="absolute inset-0 flex items-center justify-center text-[0.95rem] font-bold tracking-[0.04em] text-white whitespace-nowrap backface-hidden translate-y-full -rotate-x-90 transition-transform duration-[350ms] ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:translate-y-0 group-hover:rotate-x-0 group-focus-visible:translate-y-0 group-focus-visible:rotate-x-0 motion-reduce:translate-y-0 motion-reduce:rotate-x-0 motion-reduce:opacity-0 motion-reduce:transition-opacity motion-reduce:group-hover:opacity-100">Spots Left: 3</span>
</span>
</button>
</div>
</div>
</section>@import "tailwindcss";
@theme {
--color-tab10-bg: #0f0c1f;
--color-tab10-bg: oklch(0.14 0.04 285);
--color-tab10-mut: #818cf8;
--color-tab10-mut: oklch(0.7 0.14 279);
--color-tab10-indigo: #4f46e5;
--color-tab10-indigo: oklch(0.51 0.24 277);
--color-tab10-teal: #0d9488;
--color-tab10-teal: oklch(0.56 0.11 184);
--color-tab10-rose: #e11d48;
--color-tab10-rose: oklch(0.57 0.22 13);
--font-tab10-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tab-10 {
width: 100%;
min-height: 100svh;
}
.tab-10 ::selection {
background: var(--color-tab10-indigo);
color: #fff;
}@import "tailwindcss";
@theme {
--color-tab10-bg: #0f0c1f;
--color-tab10-bg: oklch(0.14 0.04 285);
--color-tab10-mut: #818cf8;
--color-tab10-mut: oklch(0.7 0.14 279);
--color-tab10-indigo: #4f46e5;
--color-tab10-indigo: oklch(0.51 0.24 277);
--color-tab10-teal: #0d9488;
--color-tab10-teal: oklch(0.56 0.11 184);
--color-tab10-rose: #e11d48;
--color-tab10-rose: oklch(0.57 0.22 13);
--font-tab10-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tab-10 {
width: 100%;
min-height: 100svh;
}
.tab-10 ::selection {
background: var(--color-tab10-indigo);
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-tab10-bg: #0f0c1f;
--color-tab10-bg: oklch(0.14 0.04 285);
--color-tab10-mut: #818cf8;
--color-tab10-mut: oklch(0.7 0.14 279);
--color-tab10-indigo: #4f46e5;
--color-tab10-indigo: oklch(0.51 0.24 277);
--color-tab10-teal: #0d9488;
--color-tab10-teal: oklch(0.56 0.11 184);
--color-tab10-rose: #e11d48;
--color-tab10-rose: oklch(0.57 0.22 13);
--font-tab10-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tab-10 {
width: 100%;
min-height: 100svh;
}
.tab-10 ::selection {
background: var(--color-tab10-indigo);
color: #fff;
}@import "tailwindcss";
@theme {
--color-tab10-bg: #0f0c1f;
--color-tab10-bg: oklch(0.14 0.04 285);
--color-tab10-mut: #818cf8;
--color-tab10-mut: oklch(0.7 0.14 279);
--color-tab10-indigo: #4f46e5;
--color-tab10-indigo: oklch(0.51 0.24 277);
--color-tab10-teal: #0d9488;
--color-tab10-teal: oklch(0.56 0.11 184);
--color-tab10-rose: #e11d48;
--color-tab10-rose: oklch(0.57 0.22 13);
--font-tab10-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tab-10 {
width: 100%;
min-height: 100svh;
}
.tab-10 ::selection {
background: var(--color-tab10-indigo);
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&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.
perspective-*,transform-3d,backface-hiddenandrotate-x-*are all real v4 utilities — this demo needs no arbitrary properties at all, which was not true in v3.groupis what makes the flip readable: each panel's own class list holds its resting transform and its hovered transform, instead of two parent-keyed rules.- UI change from the CSS original:
group-focus-visible:twins on both panels. The back label carries real information, so hiding it from keyboard users was a content problem.
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 Text Flip Button Hover with 3D Rotation
Source: https://codefronts.com/motion/tailwind-css-animated-buttons/tailwind-text-flip-button-hover/
The label pivots away on a horizontal axis and a second message pivots in behind it. The port's structural gain is group: the button declares it once and both panels read group-hover:, so the two halves of the flip are described on the elements that actually rotate.
## HTML
```html
<section class="tab-10 w-full min-h-svh grid place-items-center bg-tab10-bg font-tab10-sans px-6 py-10">
<div class="flex flex-col items-center gap-8">
<p class="text-[0.78rem] tracking-[0.14em] uppercase text-tab10-mut m-0">Hover to flip text</p>
<div class="flex flex-wrap justify-center gap-5">
<button type="button" class="group p-0 bg-tab10-indigo rounded-[10px] cursor-pointer perspective-[600px] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tab10-indigo">
<span class="relative block w-36 h-12 overflow-hidden transform-3d">
<span class="absolute inset-0 flex items-center justify-center text-[0.95rem] font-bold tracking-[0.04em] text-white whitespace-nowrap backface-hidden transition-transform duration-[350ms] ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:-translate-y-full group-hover:rotate-x-90 group-focus-visible:-translate-y-full group-focus-visible:rotate-x-90 motion-reduce:transition-opacity motion-reduce:group-hover:translate-y-0 motion-reduce:group-hover:rotate-x-0 motion-reduce:group-hover:opacity-0">View Pricing</span>
<span class="absolute inset-0 flex items-center justify-center text-[0.95rem] font-bold tracking-[0.04em] text-white whitespace-nowrap backface-hidden translate-y-full -rotate-x-90 transition-transform duration-[350ms] ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:translate-y-0 group-hover:rotate-x-0 group-focus-visible:translate-y-0 group-focus-visible:rotate-x-0 motion-reduce:translate-y-0 motion-reduce:rotate-x-0 motion-reduce:opacity-0 motion-reduce:transition-opacity motion-reduce:group-hover:opacity-100">From $9/mo →</span>
</span>
</button>
<button type="button" class="group p-0 bg-tab10-teal rounded-[10px] cursor-pointer perspective-[600px] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tab10-teal">
<span class="relative block w-36 h-12 overflow-hidden transform-3d">
<span class="absolute inset-0 flex items-center justify-center text-[0.95rem] font-bold tracking-[0.04em] text-white whitespace-nowrap backface-hidden transition-transform duration-[350ms] ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:-translate-y-full group-hover:rotate-x-90 group-focus-visible:-translate-y-full group-focus-visible:rotate-x-90 motion-reduce:transition-opacity motion-reduce:group-hover:translate-y-0 motion-reduce:group-hover:rotate-x-0 motion-reduce:group-hover:opacity-0">Follow Us</span>
<span class="absolute inset-0 flex items-center justify-center text-[0.95rem] font-bold tracking-[0.04em] text-white whitespace-nowrap backface-hidden translate-y-full -rotate-x-90 transition-transform duration-[350ms] ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:translate-y-0 group-hover:rotate-x-0 group-focus-visible:translate-y-0 group-focus-visible:rotate-x-0 motion-reduce:translate-y-0 motion-reduce:rotate-x-0 motion-reduce:opacity-0 motion-reduce:transition-opacity motion-reduce:group-hover:opacity-100">@codefronts</span>
</span>
</button>
<button type="button" class="group p-0 bg-tab10-rose rounded-[10px] cursor-pointer perspective-[600px] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tab10-rose">
<span class="relative block w-36 h-12 overflow-hidden transform-3d">
<span class="absolute inset-0 flex items-center justify-center text-[0.95rem] font-bold tracking-[0.04em] text-white whitespace-nowrap backface-hidden transition-transform duration-[350ms] ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:-translate-y-full group-hover:rotate-x-90 group-focus-visible:-translate-y-full group-focus-visible:rotate-x-90 motion-reduce:transition-opacity motion-reduce:group-hover:translate-y-0 motion-reduce:group-hover:rotate-x-0 motion-reduce:group-hover:opacity-0">Join Beta</span>
<span class="absolute inset-0 flex items-center justify-center text-[0.95rem] font-bold tracking-[0.04em] text-white whitespace-nowrap backface-hidden translate-y-full -rotate-x-90 transition-transform duration-[350ms] ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:translate-y-0 group-hover:rotate-x-0 group-focus-visible:translate-y-0 group-focus-visible:rotate-x-0 motion-reduce:translate-y-0 motion-reduce:rotate-x-0 motion-reduce:opacity-0 motion-reduce:transition-opacity motion-reduce:group-hover:opacity-100">Spots Left: 3</span>
</span>
</button>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tab10-bg: #0f0c1f;
--color-tab10-bg: oklch(0.14 0.04 285);
--color-tab10-mut: #818cf8;
--color-tab10-mut: oklch(0.7 0.14 279);
--color-tab10-indigo: #4f46e5;
--color-tab10-indigo: oklch(0.51 0.24 277);
--color-tab10-teal: #0d9488;
--color-tab10-teal: oklch(0.56 0.11 184);
--color-tab10-rose: #e11d48;
--color-tab10-rose: oklch(0.57 0.22 13);
--font-tab10-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tab-10 {
width: 100%;
min-height: 100svh;
}
.tab-10 ::selection {
background: var(--color-tab10-indigo);
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 Text Flip Button Hover with 3D Rotation
Source: https://codefronts.com/motion/tailwind-css-animated-buttons/tailwind-text-flip-button-hover/
The label pivots away on a horizontal axis and a second message pivots in behind it. The port's structural gain is group: the button declares it once and both panels read group-hover:, so the two halves of the flip are described on the elements that actually rotate.
## HTML
```html
<section class="tab-10 w-full min-h-svh grid place-items-center bg-tab10-bg font-tab10-sans px-6 py-10">
<div class="flex flex-col items-center gap-8">
<p class="text-[0.78rem] tracking-[0.14em] uppercase text-tab10-mut m-0">Hover to flip text</p>
<div class="flex flex-wrap justify-center gap-5">
<button type="button" class="group p-0 bg-tab10-indigo rounded-[10px] cursor-pointer perspective-[600px] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tab10-indigo">
<span class="relative block w-36 h-12 overflow-hidden transform-3d">
<span class="absolute inset-0 flex items-center justify-center text-[0.95rem] font-bold tracking-[0.04em] text-white whitespace-nowrap backface-hidden transition-transform duration-[350ms] ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:-translate-y-full group-hover:rotate-x-90 group-focus-visible:-translate-y-full group-focus-visible:rotate-x-90 motion-reduce:transition-opacity motion-reduce:group-hover:translate-y-0 motion-reduce:group-hover:rotate-x-0 motion-reduce:group-hover:opacity-0">View Pricing</span>
<span class="absolute inset-0 flex items-center justify-center text-[0.95rem] font-bold tracking-[0.04em] text-white whitespace-nowrap backface-hidden translate-y-full -rotate-x-90 transition-transform duration-[350ms] ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:translate-y-0 group-hover:rotate-x-0 group-focus-visible:translate-y-0 group-focus-visible:rotate-x-0 motion-reduce:translate-y-0 motion-reduce:rotate-x-0 motion-reduce:opacity-0 motion-reduce:transition-opacity motion-reduce:group-hover:opacity-100">From $9/mo →</span>
</span>
</button>
<button type="button" class="group p-0 bg-tab10-teal rounded-[10px] cursor-pointer perspective-[600px] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tab10-teal">
<span class="relative block w-36 h-12 overflow-hidden transform-3d">
<span class="absolute inset-0 flex items-center justify-center text-[0.95rem] font-bold tracking-[0.04em] text-white whitespace-nowrap backface-hidden transition-transform duration-[350ms] ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:-translate-y-full group-hover:rotate-x-90 group-focus-visible:-translate-y-full group-focus-visible:rotate-x-90 motion-reduce:transition-opacity motion-reduce:group-hover:translate-y-0 motion-reduce:group-hover:rotate-x-0 motion-reduce:group-hover:opacity-0">Follow Us</span>
<span class="absolute inset-0 flex items-center justify-center text-[0.95rem] font-bold tracking-[0.04em] text-white whitespace-nowrap backface-hidden translate-y-full -rotate-x-90 transition-transform duration-[350ms] ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:translate-y-0 group-hover:rotate-x-0 group-focus-visible:translate-y-0 group-focus-visible:rotate-x-0 motion-reduce:translate-y-0 motion-reduce:rotate-x-0 motion-reduce:opacity-0 motion-reduce:transition-opacity motion-reduce:group-hover:opacity-100">@codefronts</span>
</span>
</button>
<button type="button" class="group p-0 bg-tab10-rose rounded-[10px] cursor-pointer perspective-[600px] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tab10-rose">
<span class="relative block w-36 h-12 overflow-hidden transform-3d">
<span class="absolute inset-0 flex items-center justify-center text-[0.95rem] font-bold tracking-[0.04em] text-white whitespace-nowrap backface-hidden transition-transform duration-[350ms] ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:-translate-y-full group-hover:rotate-x-90 group-focus-visible:-translate-y-full group-focus-visible:rotate-x-90 motion-reduce:transition-opacity motion-reduce:group-hover:translate-y-0 motion-reduce:group-hover:rotate-x-0 motion-reduce:group-hover:opacity-0">Join Beta</span>
<span class="absolute inset-0 flex items-center justify-center text-[0.95rem] font-bold tracking-[0.04em] text-white whitespace-nowrap backface-hidden translate-y-full -rotate-x-90 transition-transform duration-[350ms] ease-[cubic-bezier(0.4,0,0.2,1)] group-hover:translate-y-0 group-hover:rotate-x-0 group-focus-visible:translate-y-0 group-focus-visible:rotate-x-0 motion-reduce:translate-y-0 motion-reduce:rotate-x-0 motion-reduce:opacity-0 motion-reduce:transition-opacity motion-reduce:group-hover:opacity-100">Spots Left: 3</span>
</span>
</button>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tab10-bg: #0f0c1f;
--color-tab10-bg: oklch(0.14 0.04 285);
--color-tab10-mut: #818cf8;
--color-tab10-mut: oklch(0.7 0.14 279);
--color-tab10-indigo: #4f46e5;
--color-tab10-indigo: oklch(0.51 0.24 277);
--color-tab10-teal: #0d9488;
--color-tab10-teal: oklch(0.56 0.11 184);
--color-tab10-rose: #e11d48;
--color-tab10-rose: oklch(0.57 0.22 13);
--font-tab10-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tab-10 {
width: 100%;
min-height: 100svh;
}
.tab-10 ::selection {
background: var(--color-tab10-indigo);
color: #fff;
}
```How this works
Two panels, one pivot. The front sits at identity; the back waits at translate-y-full rotate-x-[-90deg]. On hover the front rotates up and out while the back rotates down into place, both on the same duration and curve, so they read as one rigid object turning.
group replaces a descendant selector. The CSS version wrote .btn:hover .front and .btn:hover .back — two rules pointing inward. Tailwind puts group on the button and group-hover: on each panel, so each panel's resting and hovered transform sit in the same class list.
Focus flips too. group-focus-visible: mirrors every group-hover:, which the original did not do — the second message was mouse-only, and on a button whose back label carries real content ("From $9/mo") that is a content bug, not a polish issue.
Make it yours
- Horizontal flip: swap
rotate-x-*forrotate-y-*and thetranslate-yoffsets fortranslate-x. - Depth:
perspective-[600px]→perspective-[1200px]for a flatter, more corporate turn. - Put an icon in the back panel — it is ordinary markup, not a
contentstring.
Gotchas — read before shipping
- Drop
backface-hiddenand some engines render a mirrored ghost of the front panel through the back at 45°. - The panel stage needs a fixed height and width; a 3D flip cannot resolve against
autosizing without jumping. - If the back label is longer than the front, the button jumps width mid-flip unless the stage has an explicit
w-*— which is why the stage here isw-36.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
3D transforms with backface-visibility are universally supported; the floor is Tailwind v4's generated sheet.