01 / 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 Neon Glow Button with Pulsing Halo
A neon-lit CTA with a breathing glow halo, ported to a single class list. The port's win is --animate-tab01-pulse: the whole animation shorthand is declared once as a token, so the markup says animate-tab01-pulse and the hover override says hover:[animation-play-state:paused] — the trigger reads where the button is, not three rules away.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tab-01 w-full min-h-svh grid place-items-center bg-tab01-bg font-tab01-sans px-6 py-10">
<div class="w-[min(520px,100%)] text-center">
<p class="text-xs font-medium tracking-[0.18em] uppercase text-tab01-neon/80 m-0">Premium SaaS — Launch Your Project</p>
<h2 class="mt-3 mb-3 text-[clamp(1.8rem,4vw,2.6rem)] font-bold leading-[1.15] text-white">Build faster.<br>Ship smarter.</h2>
<p class="mb-8 text-[0.95rem] text-tab01-ink/70">Join 50,000+ developers already on the platform.</p>
<button type="button" class="inline-flex items-center justify-center gap-2 min-h-11 px-10 py-3.5 text-base font-bold uppercase tracking-[0.04em] text-white bg-transparent border-2 border-tab01-neon rounded-lg cursor-pointer animate-tab01-pulse [text-shadow:0_0_8px_var(--color-tab01-glow)] transition-[color,background-color,border-color,box-shadow] duration-300 hover:bg-tab01-neon hover:shadow-[0_0_16px_var(--color-tab01-neon),0_0_40px_var(--color-tab01-neon),inset_0_0_16px_oklch(1_0_0/0.15)] hover:[text-shadow:none] hover:[animation-play-state:paused] focus-visible:outline-3 focus-visible:outline-tab01-neon focus-visible:outline-offset-4 active:scale-[0.97] motion-reduce:animate-none motion-reduce:transition-none">Get Started Free</button>
<p class="mt-4 text-[0.78rem] text-tab01-ink/45">No credit card required · Cancel anytime</p>
</div>
</section><section class="tab-01 w-full min-h-svh grid place-items-center bg-tab01-bg font-tab01-sans px-6 py-10">
<div class="w-[min(520px,100%)] text-center">
<p class="text-xs font-medium tracking-[0.18em] uppercase text-tab01-neon/80 m-0">Premium SaaS — Launch Your Project</p>
<h2 class="mt-3 mb-3 text-[clamp(1.8rem,4vw,2.6rem)] font-bold leading-[1.15] text-white">Build faster.<br>Ship smarter.</h2>
<p class="mb-8 text-[0.95rem] text-tab01-ink/70">Join 50,000+ developers already on the platform.</p>
<button type="button" class="inline-flex items-center justify-center gap-2 min-h-11 px-10 py-3.5 text-base font-bold uppercase tracking-[0.04em] text-white bg-transparent border-2 border-tab01-neon rounded-lg cursor-pointer animate-tab01-pulse [text-shadow:0_0_8px_var(--color-tab01-glow)] transition-[color,background-color,border-color,box-shadow] duration-300 hover:bg-tab01-neon hover:shadow-[0_0_16px_var(--color-tab01-neon),0_0_40px_var(--color-tab01-neon),inset_0_0_16px_oklch(1_0_0/0.15)] hover:[text-shadow:none] hover:[animation-play-state:paused] focus-visible:outline-3 focus-visible:outline-tab01-neon focus-visible:outline-offset-4 active:scale-[0.97] motion-reduce:animate-none motion-reduce:transition-none">Get Started Free</button>
<p class="mt-4 text-[0.78rem] text-tab01-ink/45">No credit card required · Cancel anytime</p>
</div>
</section>@import "tailwindcss";
@theme {
--color-tab01-bg: #0a0010;
--color-tab01-bg: oklch(0.09 0.04 305);
--color-tab01-neon: #b829ff;
--color-tab01-neon: oklch(0.62 0.28 305);
--color-tab01-glow: #b829ff99;
--color-tab01-glow: oklch(0.62 0.28 305 / 0.6);
--color-tab01-ink: #e8d5ff;
--color-tab01-ink: oklch(0.9 0.06 305);
--font-tab01-sans: 'Space Grotesk', system-ui, sans-serif;
--animate-tab01-pulse: tab01-pulse 2s ease-in-out infinite;
}
@keyframes tab01-pulse {
0%,
100% {
box-shadow: 0 0 8px var(--color-tab01-glow), 0 0 20px var(--color-tab01-glow), inset 0 0 10px oklch(0.62 0.28 305 / 0.1);
}
50% {
box-shadow: 0 0 14px var(--color-tab01-neon), 0 0 36px var(--color-tab01-glow), 0 0 60px oklch(0.62 0.28 305 / 0.2), inset 0 0 16px oklch(0.62 0.28 305 / 0.14);
}
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
w-full min-h-svh, so the stage is sized before the browser build has compiled. */
.tab-01 {
width: 100%;
min-height: 100svh;
}
.tab-01 ::selection {
background: var(--color-tab01-neon);
color: #fff;
}@import "tailwindcss";
@theme {
--color-tab01-bg: #0a0010;
--color-tab01-bg: oklch(0.09 0.04 305);
--color-tab01-neon: #b829ff;
--color-tab01-neon: oklch(0.62 0.28 305);
--color-tab01-glow: #b829ff99;
--color-tab01-glow: oklch(0.62 0.28 305 / 0.6);
--color-tab01-ink: #e8d5ff;
--color-tab01-ink: oklch(0.9 0.06 305);
--font-tab01-sans: 'Space Grotesk', system-ui, sans-serif;
--animate-tab01-pulse: tab01-pulse 2s ease-in-out infinite;
}
@keyframes tab01-pulse {
0%,
100% {
box-shadow: 0 0 8px var(--color-tab01-glow), 0 0 20px var(--color-tab01-glow), inset 0 0 10px oklch(0.62 0.28 305 / 0.1);
}
50% {
box-shadow: 0 0 14px var(--color-tab01-neon), 0 0 36px var(--color-tab01-glow), 0 0 60px oklch(0.62 0.28 305 / 0.2), inset 0 0 16px oklch(0.62 0.28 305 / 0.14);
}
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
w-full min-h-svh, so the stage is sized before the browser build has compiled. */
.tab-01 {
width: 100%;
min-height: 100svh;
}
.tab-01 ::selection {
background: var(--color-tab01-neon);
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-tab01-bg: #0a0010;
--color-tab01-bg: oklch(0.09 0.04 305);
--color-tab01-neon: #b829ff;
--color-tab01-neon: oklch(0.62 0.28 305);
--color-tab01-glow: #b829ff99;
--color-tab01-glow: oklch(0.62 0.28 305 / 0.6);
--color-tab01-ink: #e8d5ff;
--color-tab01-ink: oklch(0.9 0.06 305);
--font-tab01-sans: 'Space Grotesk', system-ui, sans-serif;
--animate-tab01-pulse: tab01-pulse 2s ease-in-out infinite;
}
@keyframes tab01-pulse {
0%,
100% {
box-shadow: 0 0 8px var(--color-tab01-glow), 0 0 20px var(--color-tab01-glow), inset 0 0 10px oklch(0.62 0.28 305 / 0.1);
}
50% {
box-shadow: 0 0 14px var(--color-tab01-neon), 0 0 36px var(--color-tab01-glow), 0 0 60px oklch(0.62 0.28 305 / 0.2), inset 0 0 16px oklch(0.62 0.28 305 / 0.14);
}
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
w-full min-h-svh, so the stage is sized before the browser build has compiled. */
.tab-01 {
width: 100%;
min-height: 100svh;
}
.tab-01 ::selection {
background: var(--color-tab01-neon);
color: #fff;
}@import "tailwindcss";
@theme {
--color-tab01-bg: #0a0010;
--color-tab01-bg: oklch(0.09 0.04 305);
--color-tab01-neon: #b829ff;
--color-tab01-neon: oklch(0.62 0.28 305);
--color-tab01-glow: #b829ff99;
--color-tab01-glow: oklch(0.62 0.28 305 / 0.6);
--color-tab01-ink: #e8d5ff;
--color-tab01-ink: oklch(0.9 0.06 305);
--font-tab01-sans: 'Space Grotesk', system-ui, sans-serif;
--animate-tab01-pulse: tab01-pulse 2s ease-in-out infinite;
}
@keyframes tab01-pulse {
0%,
100% {
box-shadow: 0 0 8px var(--color-tab01-glow), 0 0 20px var(--color-tab01-glow), inset 0 0 10px oklch(0.62 0.28 305 / 0.1);
}
50% {
box-shadow: 0 0 14px var(--color-tab01-neon), 0 0 36px var(--color-tab01-glow), 0 0 60px oklch(0.62 0.28 305 / 0.2), inset 0 0 16px oklch(0.62 0.28 305 / 0.14);
}
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
w-full min-h-svh, so the stage is sized before the browser build has compiled. */
.tab-01 {
width: 100%;
min-height: 100svh;
}
.tab-01 ::selection {
background: var(--color-tab01-neon);
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
@keyframesstays hand-written; only its binding becomes a utility. That split is the honest answer for every animated demo in this collection — a timeline is not a design-scale value. - The pulse and the hover halo are the same four shadow layers at different intensities, and both now read
var(--color-tab01-neon)rather than a repeated literal. - UI change from the CSS original: added a real
focus-visiblering and a 44px minimum height. The original relied on the decorative glow as its only focus signal.
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 Neon Glow Button with Pulsing Halo
Source: https://codefronts.com/motion/tailwind-css-animated-buttons/tailwind-neon-glow-button-pulsing-halo/
A neon-lit CTA with a breathing glow halo, ported to a single class list. The port's win is --animate-tab01-pulse: the whole animation shorthand is declared once as a token, so the markup says animate-tab01-pulse and the hover override says hover:[animation-play-state:paused] — the trigger reads where the button is, not three rules away.
## HTML
```html
<section class="tab-01 w-full min-h-svh grid place-items-center bg-tab01-bg font-tab01-sans px-6 py-10">
<div class="w-[min(520px,100%)] text-center">
<p class="text-xs font-medium tracking-[0.18em] uppercase text-tab01-neon/80 m-0">Premium SaaS — Launch Your Project</p>
<h2 class="mt-3 mb-3 text-[clamp(1.8rem,4vw,2.6rem)] font-bold leading-[1.15] text-white">Build faster.<br>Ship smarter.</h2>
<p class="mb-8 text-[0.95rem] text-tab01-ink/70">Join 50,000+ developers already on the platform.</p>
<button type="button" class="inline-flex items-center justify-center gap-2 min-h-11 px-10 py-3.5 text-base font-bold uppercase tracking-[0.04em] text-white bg-transparent border-2 border-tab01-neon rounded-lg cursor-pointer animate-tab01-pulse [text-shadow:0_0_8px_var(--color-tab01-glow)] transition-[color,background-color,border-color,box-shadow] duration-300 hover:bg-tab01-neon hover:shadow-[0_0_16px_var(--color-tab01-neon),0_0_40px_var(--color-tab01-neon),inset_0_0_16px_oklch(1_0_0/0.15)] hover:[text-shadow:none] hover:[animation-play-state:paused] focus-visible:outline-3 focus-visible:outline-tab01-neon focus-visible:outline-offset-4 active:scale-[0.97] motion-reduce:animate-none motion-reduce:transition-none">Get Started Free</button>
<p class="mt-4 text-[0.78rem] text-tab01-ink/45">No credit card required · Cancel anytime</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tab01-bg: #0a0010;
--color-tab01-bg: oklch(0.09 0.04 305);
--color-tab01-neon: #b829ff;
--color-tab01-neon: oklch(0.62 0.28 305);
--color-tab01-glow: #b829ff99;
--color-tab01-glow: oklch(0.62 0.28 305 / 0.6);
--color-tab01-ink: #e8d5ff;
--color-tab01-ink: oklch(0.9 0.06 305);
--font-tab01-sans: 'Space Grotesk', system-ui, sans-serif;
--animate-tab01-pulse: tab01-pulse 2s ease-in-out infinite;
}
@keyframes tab01-pulse {
0%,
100% {
box-shadow: 0 0 8px var(--color-tab01-glow), 0 0 20px var(--color-tab01-glow), inset 0 0 10px oklch(0.62 0.28 305 / 0.1);
}
50% {
box-shadow: 0 0 14px var(--color-tab01-neon), 0 0 36px var(--color-tab01-glow), 0 0 60px oklch(0.62 0.28 305 / 0.2), inset 0 0 16px oklch(0.62 0.28 305 / 0.14);
}
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
w-full min-h-svh, so the stage is sized before the browser build has compiled. */
.tab-01 {
width: 100%;
min-height: 100svh;
}
.tab-01 ::selection {
background: var(--color-tab01-neon);
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 Neon Glow Button with Pulsing Halo
Source: https://codefronts.com/motion/tailwind-css-animated-buttons/tailwind-neon-glow-button-pulsing-halo/
A neon-lit CTA with a breathing glow halo, ported to a single class list. The port's win is --animate-tab01-pulse: the whole animation shorthand is declared once as a token, so the markup says animate-tab01-pulse and the hover override says hover:[animation-play-state:paused] — the trigger reads where the button is, not three rules away.
## HTML
```html
<section class="tab-01 w-full min-h-svh grid place-items-center bg-tab01-bg font-tab01-sans px-6 py-10">
<div class="w-[min(520px,100%)] text-center">
<p class="text-xs font-medium tracking-[0.18em] uppercase text-tab01-neon/80 m-0">Premium SaaS — Launch Your Project</p>
<h2 class="mt-3 mb-3 text-[clamp(1.8rem,4vw,2.6rem)] font-bold leading-[1.15] text-white">Build faster.<br>Ship smarter.</h2>
<p class="mb-8 text-[0.95rem] text-tab01-ink/70">Join 50,000+ developers already on the platform.</p>
<button type="button" class="inline-flex items-center justify-center gap-2 min-h-11 px-10 py-3.5 text-base font-bold uppercase tracking-[0.04em] text-white bg-transparent border-2 border-tab01-neon rounded-lg cursor-pointer animate-tab01-pulse [text-shadow:0_0_8px_var(--color-tab01-glow)] transition-[color,background-color,border-color,box-shadow] duration-300 hover:bg-tab01-neon hover:shadow-[0_0_16px_var(--color-tab01-neon),0_0_40px_var(--color-tab01-neon),inset_0_0_16px_oklch(1_0_0/0.15)] hover:[text-shadow:none] hover:[animation-play-state:paused] focus-visible:outline-3 focus-visible:outline-tab01-neon focus-visible:outline-offset-4 active:scale-[0.97] motion-reduce:animate-none motion-reduce:transition-none">Get Started Free</button>
<p class="mt-4 text-[0.78rem] text-tab01-ink/45">No credit card required · Cancel anytime</p>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tab01-bg: #0a0010;
--color-tab01-bg: oklch(0.09 0.04 305);
--color-tab01-neon: #b829ff;
--color-tab01-neon: oklch(0.62 0.28 305);
--color-tab01-glow: #b829ff99;
--color-tab01-glow: oklch(0.62 0.28 305 / 0.6);
--color-tab01-ink: #e8d5ff;
--color-tab01-ink: oklch(0.9 0.06 305);
--font-tab01-sans: 'Space Grotesk', system-ui, sans-serif;
--animate-tab01-pulse: tab01-pulse 2s ease-in-out infinite;
}
@keyframes tab01-pulse {
0%,
100% {
box-shadow: 0 0 8px var(--color-tab01-glow), 0 0 20px var(--color-tab01-glow), inset 0 0 10px oklch(0.62 0.28 305 / 0.1);
}
50% {
box-shadow: 0 0 14px var(--color-tab01-neon), 0 0 36px var(--color-tab01-glow), 0 0 60px oklch(0.62 0.28 305 / 0.2), inset 0 0 16px oklch(0.62 0.28 305 / 0.14);
}
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's
w-full min-h-svh, so the stage is sized before the browser build has compiled. */
.tab-01 {
width: 100%;
min-height: 100svh;
}
.tab-01 ::selection {
background: var(--color-tab01-neon);
color: #fff;
}
```How this works
The animation binding moves into the markup. The keyframe stays in CSS — there is no utility syntax for a timeline — but the shorthand becomes a token:
--animate-tab01-pulse: tab01-pulse 2s ease-in-out infinite;and the element carries animate-tab01-pulse. Change the mood in one place (the token) or move where it fires (the class list) without touching the other.
One colour token drives four properties. border-tab01-neon, hover:bg-tab01-neon, the arbitrary shadow-[…var(--color-tab01-neon)…] and the [text-shadow:…] all read --color-tab01-neon. Retheming is a one-line edit, exactly as the CSS custom-property version promised, but now the derived values are visible on the element.
The glow is not the focus indicator. The original set outline:none and relied on the halo, which is a decorative animation a keyboard user cannot distinguish. This version adds focus-visible:outline-3 focus-visible:outline-offset-4, a real ring on top of the glow.
Make it yours
- Retheme through
--color-tab01-neon— border, fill, halo and text-shadow all derive from it. - Pulse speed lives in the token:
--animate-tab01-pulse: tab01-pulse 1s …for urgency,4sfor ambient. - For hero placements, scale the halo by editing the arbitrary shadow blur values (
0_0_40px→0_0_80px).
Gotchas — read before shipping
- An outer glow is still clipped by any ancestor with
overflow-hidden— the utility version does not change stacking-context physics. - Blur radii past ~60px can jitter on Chrome/Windows with some GPU drivers; test on target hardware before shipping a bigger halo.
animate-noneundermotion-reduce:must come with a retained hover state. Removing the animation and nothing else leaves the button with no feedback at all.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
Box-shadow and text-shadow animation are universally supported; the floor quoted is Tailwind v4's own generated sheet.