05 / 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 3D Press Effect Button with Keycap Depth
A keycap that physically sinks into its own platform. Two properties do all the work, and as utilities the resting and pressed states sit side by side: shadow-[0_6px_0_…] becomes active:shadow-[0_2px_0_…] while the face drops active:translate-y-1.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tab-05 w-full min-h-svh grid place-items-center bg-tab05-bg font-tab05-sans px-6 py-10">
<div class="flex flex-col items-center gap-10">
<p class="text-[0.78rem] tracking-[0.12em] uppercase text-tab05-mut m-0">Click or tap the buttons</p>
<div class="flex flex-wrap justify-center gap-5">
<button type="button" class="min-h-11 px-9 text-base font-bold tracking-[0.03em] text-white bg-tab05-indigo rounded-[10px] cursor-pointer select-none transition-[translate,box-shadow] duration-[80ms] shadow-[0_6px_0_var(--color-tab05-indigo-deep),0_8px_12px_oklch(0_0_0/0.18)] hover:brightness-105 active:translate-y-1 active:shadow-[0_2px_0_var(--color-tab05-indigo-deep),0_4px_6px_oklch(0_0_0/0.12)] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tab05-indigo motion-reduce:transition-none">Purchase Now</button>
<button type="button" class="min-h-11 px-9 text-base font-bold tracking-[0.03em] text-white bg-tab05-emerald rounded-[10px] cursor-pointer select-none transition-[translate,box-shadow] duration-[80ms] shadow-[0_6px_0_var(--color-tab05-emerald-deep),0_8px_12px_oklch(0_0_0/0.18)] hover:brightness-105 active:translate-y-1 active:shadow-[0_2px_0_var(--color-tab05-emerald-deep),0_4px_6px_oklch(0_0_0/0.12)] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tab05-emerald motion-reduce:transition-none">Download App</button>
<button type="button" class="min-h-11 px-9 text-base font-bold tracking-[0.03em] text-white bg-tab05-rose rounded-[10px] cursor-pointer select-none transition-[translate,box-shadow] duration-[80ms] shadow-[0_6px_0_var(--color-tab05-rose-deep),0_8px_12px_oklch(0_0_0/0.18)] hover:brightness-105 active:translate-y-1 active:shadow-[0_2px_0_var(--color-tab05-rose-deep),0_4px_6px_oklch(0_0_0/0.12)] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tab05-rose motion-reduce:transition-none">Delete File</button>
</div>
</div>
</section><section class="tab-05 w-full min-h-svh grid place-items-center bg-tab05-bg font-tab05-sans px-6 py-10">
<div class="flex flex-col items-center gap-10">
<p class="text-[0.78rem] tracking-[0.12em] uppercase text-tab05-mut m-0">Click or tap the buttons</p>
<div class="flex flex-wrap justify-center gap-5">
<button type="button" class="min-h-11 px-9 text-base font-bold tracking-[0.03em] text-white bg-tab05-indigo rounded-[10px] cursor-pointer select-none transition-[translate,box-shadow] duration-[80ms] shadow-[0_6px_0_var(--color-tab05-indigo-deep),0_8px_12px_oklch(0_0_0/0.18)] hover:brightness-105 active:translate-y-1 active:shadow-[0_2px_0_var(--color-tab05-indigo-deep),0_4px_6px_oklch(0_0_0/0.12)] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tab05-indigo motion-reduce:transition-none">Purchase Now</button>
<button type="button" class="min-h-11 px-9 text-base font-bold tracking-[0.03em] text-white bg-tab05-emerald rounded-[10px] cursor-pointer select-none transition-[translate,box-shadow] duration-[80ms] shadow-[0_6px_0_var(--color-tab05-emerald-deep),0_8px_12px_oklch(0_0_0/0.18)] hover:brightness-105 active:translate-y-1 active:shadow-[0_2px_0_var(--color-tab05-emerald-deep),0_4px_6px_oklch(0_0_0/0.12)] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tab05-emerald motion-reduce:transition-none">Download App</button>
<button type="button" class="min-h-11 px-9 text-base font-bold tracking-[0.03em] text-white bg-tab05-rose rounded-[10px] cursor-pointer select-none transition-[translate,box-shadow] duration-[80ms] shadow-[0_6px_0_var(--color-tab05-rose-deep),0_8px_12px_oklch(0_0_0/0.18)] hover:brightness-105 active:translate-y-1 active:shadow-[0_2px_0_var(--color-tab05-rose-deep),0_4px_6px_oklch(0_0_0/0.12)] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tab05-rose motion-reduce:transition-none">Delete File</button>
</div>
</div>
</section>@import "tailwindcss";
@theme {
--color-tab05-bg: #f8fafc;
--color-tab05-bg: oklch(0.98 0.004 250);
--color-tab05-mut: #64748b;
--color-tab05-mut: oklch(0.55 0.03 255);
--color-tab05-indigo: #6366f1;
--color-tab05-indigo: oklch(0.58 0.21 277);
--color-tab05-indigo-deep: #3730a3;
--color-tab05-indigo-deep: oklch(0.38 0.17 277);
--color-tab05-emerald: #10b981;
--color-tab05-emerald: oklch(0.7 0.15 163);
--color-tab05-emerald-deep: #065f46;
--color-tab05-emerald-deep: oklch(0.42 0.09 163);
--color-tab05-rose: #f43f5e;
--color-tab05-rose: oklch(0.63 0.22 15);
--color-tab05-rose-deep: #9f1239;
--color-tab05-rose-deep: oklch(0.42 0.16 15);
--font-tab05-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tab-05 {
width: 100%;
min-height: 100svh;
}
.tab-05 ::selection {
background: var(--color-tab05-indigo);
color: #fff;
}@import "tailwindcss";
@theme {
--color-tab05-bg: #f8fafc;
--color-tab05-bg: oklch(0.98 0.004 250);
--color-tab05-mut: #64748b;
--color-tab05-mut: oklch(0.55 0.03 255);
--color-tab05-indigo: #6366f1;
--color-tab05-indigo: oklch(0.58 0.21 277);
--color-tab05-indigo-deep: #3730a3;
--color-tab05-indigo-deep: oklch(0.38 0.17 277);
--color-tab05-emerald: #10b981;
--color-tab05-emerald: oklch(0.7 0.15 163);
--color-tab05-emerald-deep: #065f46;
--color-tab05-emerald-deep: oklch(0.42 0.09 163);
--color-tab05-rose: #f43f5e;
--color-tab05-rose: oklch(0.63 0.22 15);
--color-tab05-rose-deep: #9f1239;
--color-tab05-rose-deep: oklch(0.42 0.16 15);
--font-tab05-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tab-05 {
width: 100%;
min-height: 100svh;
}
.tab-05 ::selection {
background: var(--color-tab05-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-tab05-bg: #f8fafc;
--color-tab05-bg: oklch(0.98 0.004 250);
--color-tab05-mut: #64748b;
--color-tab05-mut: oklch(0.55 0.03 255);
--color-tab05-indigo: #6366f1;
--color-tab05-indigo: oklch(0.58 0.21 277);
--color-tab05-indigo-deep: #3730a3;
--color-tab05-indigo-deep: oklch(0.38 0.17 277);
--color-tab05-emerald: #10b981;
--color-tab05-emerald: oklch(0.7 0.15 163);
--color-tab05-emerald-deep: #065f46;
--color-tab05-emerald-deep: oklch(0.42 0.09 163);
--color-tab05-rose: #f43f5e;
--color-tab05-rose: oklch(0.63 0.22 15);
--color-tab05-rose-deep: #9f1239;
--color-tab05-rose-deep: oklch(0.42 0.16 15);
--font-tab05-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tab-05 {
width: 100%;
min-height: 100svh;
}
.tab-05 ::selection {
background: var(--color-tab05-indigo);
color: #fff;
}@import "tailwindcss";
@theme {
--color-tab05-bg: #f8fafc;
--color-tab05-bg: oklch(0.98 0.004 250);
--color-tab05-mut: #64748b;
--color-tab05-mut: oklch(0.55 0.03 255);
--color-tab05-indigo: #6366f1;
--color-tab05-indigo: oklch(0.58 0.21 277);
--color-tab05-indigo-deep: #3730a3;
--color-tab05-indigo-deep: oklch(0.38 0.17 277);
--color-tab05-emerald: #10b981;
--color-tab05-emerald: oklch(0.7 0.15 163);
--color-tab05-emerald-deep: #065f46;
--color-tab05-emerald-deep: oklch(0.42 0.09 163);
--color-tab05-rose: #f43f5e;
--color-tab05-rose: oklch(0.63 0.22 15);
--color-tab05-rose-deep: #9f1239;
--color-tab05-rose-deep: oklch(0.42 0.16 15);
--font-tab05-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tab-05 {
width: 100%;
min-height: 100svh;
}
.tab-05 ::selection {
background: var(--color-tab05-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.
- The face/depth colour pair becomes two
@themeentries per variant, and the shadow utility reads both by name. The CSS version used two local custom properties per button; tokens make the pairing reusable across a real design system. transition-[translate,box-shadow]rather thantransition-all: the press must not accidentally tweenfilter, which the hover state owns.- UI change from the CSS original: a
focus-visiblering with 4px offset, clear of the depth shadow so it is not lost against the underhang.
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 Press Effect Button with Keycap Depth
Source: https://codefronts.com/motion/tailwind-css-animated-buttons/tailwind-3d-press-effect-button/
A keycap that physically sinks into its own platform. Two properties do all the work, and as utilities the resting and pressed states sit side by side: shadow-[0_6px_0_…] becomes active:shadow-[0_2px_0_…] while the face drops active:translate-y-1.
## HTML
```html
<section class="tab-05 w-full min-h-svh grid place-items-center bg-tab05-bg font-tab05-sans px-6 py-10">
<div class="flex flex-col items-center gap-10">
<p class="text-[0.78rem] tracking-[0.12em] uppercase text-tab05-mut m-0">Click or tap the buttons</p>
<div class="flex flex-wrap justify-center gap-5">
<button type="button" class="min-h-11 px-9 text-base font-bold tracking-[0.03em] text-white bg-tab05-indigo rounded-[10px] cursor-pointer select-none transition-[translate,box-shadow] duration-[80ms] shadow-[0_6px_0_var(--color-tab05-indigo-deep),0_8px_12px_oklch(0_0_0/0.18)] hover:brightness-105 active:translate-y-1 active:shadow-[0_2px_0_var(--color-tab05-indigo-deep),0_4px_6px_oklch(0_0_0/0.12)] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tab05-indigo motion-reduce:transition-none">Purchase Now</button>
<button type="button" class="min-h-11 px-9 text-base font-bold tracking-[0.03em] text-white bg-tab05-emerald rounded-[10px] cursor-pointer select-none transition-[translate,box-shadow] duration-[80ms] shadow-[0_6px_0_var(--color-tab05-emerald-deep),0_8px_12px_oklch(0_0_0/0.18)] hover:brightness-105 active:translate-y-1 active:shadow-[0_2px_0_var(--color-tab05-emerald-deep),0_4px_6px_oklch(0_0_0/0.12)] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tab05-emerald motion-reduce:transition-none">Download App</button>
<button type="button" class="min-h-11 px-9 text-base font-bold tracking-[0.03em] text-white bg-tab05-rose rounded-[10px] cursor-pointer select-none transition-[translate,box-shadow] duration-[80ms] shadow-[0_6px_0_var(--color-tab05-rose-deep),0_8px_12px_oklch(0_0_0/0.18)] hover:brightness-105 active:translate-y-1 active:shadow-[0_2px_0_var(--color-tab05-rose-deep),0_4px_6px_oklch(0_0_0/0.12)] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tab05-rose motion-reduce:transition-none">Delete File</button>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tab05-bg: #f8fafc;
--color-tab05-bg: oklch(0.98 0.004 250);
--color-tab05-mut: #64748b;
--color-tab05-mut: oklch(0.55 0.03 255);
--color-tab05-indigo: #6366f1;
--color-tab05-indigo: oklch(0.58 0.21 277);
--color-tab05-indigo-deep: #3730a3;
--color-tab05-indigo-deep: oklch(0.38 0.17 277);
--color-tab05-emerald: #10b981;
--color-tab05-emerald: oklch(0.7 0.15 163);
--color-tab05-emerald-deep: #065f46;
--color-tab05-emerald-deep: oklch(0.42 0.09 163);
--color-tab05-rose: #f43f5e;
--color-tab05-rose: oklch(0.63 0.22 15);
--color-tab05-rose-deep: #9f1239;
--color-tab05-rose-deep: oklch(0.42 0.16 15);
--font-tab05-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tab-05 {
width: 100%;
min-height: 100svh;
}
.tab-05 ::selection {
background: var(--color-tab05-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 3D Press Effect Button with Keycap Depth
Source: https://codefronts.com/motion/tailwind-css-animated-buttons/tailwind-3d-press-effect-button/
A keycap that physically sinks into its own platform. Two properties do all the work, and as utilities the resting and pressed states sit side by side: shadow-[0_6px_0_…] becomes active:shadow-[0_2px_0_…] while the face drops active:translate-y-1.
## HTML
```html
<section class="tab-05 w-full min-h-svh grid place-items-center bg-tab05-bg font-tab05-sans px-6 py-10">
<div class="flex flex-col items-center gap-10">
<p class="text-[0.78rem] tracking-[0.12em] uppercase text-tab05-mut m-0">Click or tap the buttons</p>
<div class="flex flex-wrap justify-center gap-5">
<button type="button" class="min-h-11 px-9 text-base font-bold tracking-[0.03em] text-white bg-tab05-indigo rounded-[10px] cursor-pointer select-none transition-[translate,box-shadow] duration-[80ms] shadow-[0_6px_0_var(--color-tab05-indigo-deep),0_8px_12px_oklch(0_0_0/0.18)] hover:brightness-105 active:translate-y-1 active:shadow-[0_2px_0_var(--color-tab05-indigo-deep),0_4px_6px_oklch(0_0_0/0.12)] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tab05-indigo motion-reduce:transition-none">Purchase Now</button>
<button type="button" class="min-h-11 px-9 text-base font-bold tracking-[0.03em] text-white bg-tab05-emerald rounded-[10px] cursor-pointer select-none transition-[translate,box-shadow] duration-[80ms] shadow-[0_6px_0_var(--color-tab05-emerald-deep),0_8px_12px_oklch(0_0_0/0.18)] hover:brightness-105 active:translate-y-1 active:shadow-[0_2px_0_var(--color-tab05-emerald-deep),0_4px_6px_oklch(0_0_0/0.12)] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tab05-emerald motion-reduce:transition-none">Download App</button>
<button type="button" class="min-h-11 px-9 text-base font-bold tracking-[0.03em] text-white bg-tab05-rose rounded-[10px] cursor-pointer select-none transition-[translate,box-shadow] duration-[80ms] shadow-[0_6px_0_var(--color-tab05-rose-deep),0_8px_12px_oklch(0_0_0/0.18)] hover:brightness-105 active:translate-y-1 active:shadow-[0_2px_0_var(--color-tab05-rose-deep),0_4px_6px_oklch(0_0_0/0.12)] focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-tab05-rose motion-reduce:transition-none">Delete File</button>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tab05-bg: #f8fafc;
--color-tab05-bg: oklch(0.98 0.004 250);
--color-tab05-mut: #64748b;
--color-tab05-mut: oklch(0.55 0.03 255);
--color-tab05-indigo: #6366f1;
--color-tab05-indigo: oklch(0.58 0.21 277);
--color-tab05-indigo-deep: #3730a3;
--color-tab05-indigo-deep: oklch(0.38 0.17 277);
--color-tab05-emerald: #10b981;
--color-tab05-emerald: oklch(0.7 0.15 163);
--color-tab05-emerald-deep: #065f46;
--color-tab05-emerald-deep: oklch(0.42 0.09 163);
--color-tab05-rose: #f43f5e;
--color-tab05-rose: oklch(0.63 0.22 15);
--color-tab05-rose-deep: #9f1239;
--color-tab05-rose-deep: oklch(0.42 0.16 15);
--font-tab05-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tab-05 {
width: 100%;
min-height: 100svh;
}
.tab-05 ::selection {
background: var(--color-tab05-indigo);
color: #fff;
}
```How this works
The depth is a shadow with zero blur. 0 6px 0 in a darker shade of the face reads as solid material under the button. Pressing moves the face down 4px and shrinks the underhang to 2px, so the total height stays honest and the gap appears compressed.
80ms is the technique. Real keys have no easing you can perceive. The utility version states the duration where the press states are, which makes it obvious that this is deliberately far shorter than the 200-300ms used elsewhere in the collection.
Keyboard users get the press too. focus-visible: supplies a ring, and active: fires on Space as well as pointer press — so the tactile payload is not mouse-only.
Make it yours
- Deeper travel:
shadow-[0_10px_0_…]withactive:translate-y-2— keep the two numbers in step. - New colour: set a face token and a depth token roughly 20% darker in the same hue.
- Add a top bevel with an extra
inset_0_1px_0_oklch(1_0_0/0.25)layer in the resting shadow.
Gotchas — read before shipping
- Inside an already-transformed ancestor the
active:translate-y-1composes with the parent transform — always test in context, not in isolation. - If the depth shadow and the press translate disagree by even a pixel the button appears to bounce; change them together.
select-noneis not cosmetic here. Without it, a fast double-tap selects the label and drops the:activestate mid-press.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
Transforms and box-shadows are universally supported; the floor is Tailwind v4's generated sheet.