04 / 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 Animated Border Draw Button with Staged Delays
A border that draws itself around the perimeter on hover, two pseudo-elements sharing the work. The port's real content is timing: before:delay-0, before:transition-[width,height] and a staggered after:delay-[400ms] put the whole four-stage cascade in the class list instead of a comment.
Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time
Untitled UI React · Affiliate link
The code
<section class="tab-04 w-full min-h-svh grid place-items-center bg-tab04-bg font-tab04-sans px-6 py-10">
<div class="flex flex-col items-center gap-10">
<p class="text-[0.78rem] tracking-[0.14em] uppercase text-tab04-indigo/70 m-0">Hover to draw the border</p>
<div class="flex flex-wrap justify-center gap-5">
<button type="button" class="relative min-h-11 px-9 text-[0.95rem] font-bold tracking-[0.04em] text-tab04-indigo bg-transparent cursor-pointer transition-[color,background-color] duration-[400ms] hover:text-white hover:bg-tab04-indigo/12 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tab04-indigo before:content-[''] before:absolute before:top-0 before:left-0 before:size-0 before:border-t-2 before:border-r-2 before:border-tab04-indigo before:pointer-events-none before:transition-[width,height] before:duration-200 after:content-[''] after:absolute after:right-0 after:bottom-0 after:size-0 after:border-b-2 after:border-l-2 after:border-tab04-indigo after:pointer-events-none after:transition-[width,height] after:duration-200 after:delay-[400ms] hover:before:size-full hover:after:size-full motion-reduce:before:size-full motion-reduce:after:size-full motion-reduce:before:transition-none motion-reduce:after:transition-none"><span class="relative z-10">Explore Docs</span></button>
<button type="button" class="relative min-h-11 px-9 text-[0.95rem] font-bold tracking-[0.04em] text-tab04-emerald bg-transparent cursor-pointer transition-[color,background-color] duration-[400ms] hover:text-white hover:bg-tab04-emerald/12 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tab04-emerald before:content-[''] before:absolute before:top-0 before:left-0 before:size-0 before:border-t-2 before:border-r-2 before:border-tab04-emerald before:pointer-events-none before:transition-[width,height] before:duration-200 after:content-[''] after:absolute after:right-0 after:bottom-0 after:size-0 after:border-b-2 after:border-l-2 after:border-tab04-emerald after:pointer-events-none after:transition-[width,height] after:duration-200 after:delay-[400ms] hover:before:size-full hover:after:size-full motion-reduce:before:size-full motion-reduce:after:size-full motion-reduce:before:transition-none motion-reduce:after:transition-none"><span class="relative z-10">Start Building</span></button>
<button type="button" class="relative min-h-11 px-9 text-[0.95rem] font-bold tracking-[0.04em] text-tab04-rose bg-transparent cursor-pointer transition-[color,background-color] duration-[400ms] hover:text-white hover:bg-tab04-rose/12 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tab04-rose before:content-[''] before:absolute before:top-0 before:left-0 before:size-0 before:border-t-2 before:border-r-2 before:border-tab04-rose before:pointer-events-none before:transition-[width,height] before:duration-200 after:content-[''] after:absolute after:right-0 after:bottom-0 after:size-0 after:border-b-2 after:border-l-2 after:border-tab04-rose after:pointer-events-none after:transition-[width,height] after:duration-200 after:delay-[400ms] hover:before:size-full hover:after:size-full motion-reduce:before:size-full motion-reduce:after:size-full motion-reduce:before:transition-none motion-reduce:after:transition-none"><span class="relative z-10">Contact Sales</span></button>
</div>
</div>
</section><section class="tab-04 w-full min-h-svh grid place-items-center bg-tab04-bg font-tab04-sans px-6 py-10">
<div class="flex flex-col items-center gap-10">
<p class="text-[0.78rem] tracking-[0.14em] uppercase text-tab04-indigo/70 m-0">Hover to draw the border</p>
<div class="flex flex-wrap justify-center gap-5">
<button type="button" class="relative min-h-11 px-9 text-[0.95rem] font-bold tracking-[0.04em] text-tab04-indigo bg-transparent cursor-pointer transition-[color,background-color] duration-[400ms] hover:text-white hover:bg-tab04-indigo/12 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tab04-indigo before:content-[''] before:absolute before:top-0 before:left-0 before:size-0 before:border-t-2 before:border-r-2 before:border-tab04-indigo before:pointer-events-none before:transition-[width,height] before:duration-200 after:content-[''] after:absolute after:right-0 after:bottom-0 after:size-0 after:border-b-2 after:border-l-2 after:border-tab04-indigo after:pointer-events-none after:transition-[width,height] after:duration-200 after:delay-[400ms] hover:before:size-full hover:after:size-full motion-reduce:before:size-full motion-reduce:after:size-full motion-reduce:before:transition-none motion-reduce:after:transition-none"><span class="relative z-10">Explore Docs</span></button>
<button type="button" class="relative min-h-11 px-9 text-[0.95rem] font-bold tracking-[0.04em] text-tab04-emerald bg-transparent cursor-pointer transition-[color,background-color] duration-[400ms] hover:text-white hover:bg-tab04-emerald/12 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tab04-emerald before:content-[''] before:absolute before:top-0 before:left-0 before:size-0 before:border-t-2 before:border-r-2 before:border-tab04-emerald before:pointer-events-none before:transition-[width,height] before:duration-200 after:content-[''] after:absolute after:right-0 after:bottom-0 after:size-0 after:border-b-2 after:border-l-2 after:border-tab04-emerald after:pointer-events-none after:transition-[width,height] after:duration-200 after:delay-[400ms] hover:before:size-full hover:after:size-full motion-reduce:before:size-full motion-reduce:after:size-full motion-reduce:before:transition-none motion-reduce:after:transition-none"><span class="relative z-10">Start Building</span></button>
<button type="button" class="relative min-h-11 px-9 text-[0.95rem] font-bold tracking-[0.04em] text-tab04-rose bg-transparent cursor-pointer transition-[color,background-color] duration-[400ms] hover:text-white hover:bg-tab04-rose/12 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tab04-rose before:content-[''] before:absolute before:top-0 before:left-0 before:size-0 before:border-t-2 before:border-r-2 before:border-tab04-rose before:pointer-events-none before:transition-[width,height] before:duration-200 after:content-[''] after:absolute after:right-0 after:bottom-0 after:size-0 after:border-b-2 after:border-l-2 after:border-tab04-rose after:pointer-events-none after:transition-[width,height] after:duration-200 after:delay-[400ms] hover:before:size-full hover:after:size-full motion-reduce:before:size-full motion-reduce:after:size-full motion-reduce:before:transition-none motion-reduce:after:transition-none"><span class="relative z-10">Contact Sales</span></button>
</div>
</div>
</section>@import "tailwindcss";
@theme {
--color-tab04-bg: #09090f;
--color-tab04-bg: oklch(0.1 0.01 275);
--color-tab04-indigo: #818cf8;
--color-tab04-indigo: oklch(0.7 0.14 279);
--color-tab04-emerald: #34d399;
--color-tab04-emerald: oklch(0.78 0.15 165);
--color-tab04-rose: #fb7185;
--color-tab04-rose: oklch(0.71 0.17 13);
--font-tab04-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tab-04 {
width: 100%;
min-height: 100svh;
}
.tab-04 ::selection {
background: var(--color-tab04-indigo);
color: #0b0b12;
}@import "tailwindcss";
@theme {
--color-tab04-bg: #09090f;
--color-tab04-bg: oklch(0.1 0.01 275);
--color-tab04-indigo: #818cf8;
--color-tab04-indigo: oklch(0.7 0.14 279);
--color-tab04-emerald: #34d399;
--color-tab04-emerald: oklch(0.78 0.15 165);
--color-tab04-rose: #fb7185;
--color-tab04-rose: oklch(0.71 0.17 13);
--font-tab04-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tab-04 {
width: 100%;
min-height: 100svh;
}
.tab-04 ::selection {
background: var(--color-tab04-indigo);
color: #0b0b12;
}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-tab04-bg: #09090f;
--color-tab04-bg: oklch(0.1 0.01 275);
--color-tab04-indigo: #818cf8;
--color-tab04-indigo: oklch(0.7 0.14 279);
--color-tab04-emerald: #34d399;
--color-tab04-emerald: oklch(0.78 0.15 165);
--color-tab04-rose: #fb7185;
--color-tab04-rose: oklch(0.71 0.17 13);
--font-tab04-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tab-04 {
width: 100%;
min-height: 100svh;
}
.tab-04 ::selection {
background: var(--color-tab04-indigo);
color: #0b0b12;
}@import "tailwindcss";
@theme {
--color-tab04-bg: #09090f;
--color-tab04-bg: oklch(0.1 0.01 275);
--color-tab04-indigo: #818cf8;
--color-tab04-indigo: oklch(0.7 0.14 279);
--color-tab04-emerald: #34d399;
--color-tab04-emerald: oklch(0.78 0.15 165);
--color-tab04-rose: #fb7185;
--color-tab04-rose: oklch(0.71 0.17 13);
--font-tab04-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tab-04 {
width: 100%;
min-height: 100svh;
}
.tab-04 ::selection {
background: var(--color-tab04-indigo);
color: #0b0b12;
}<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.
- A compound
transition: width .2s ease, height .2s ease .2sshorthand becomestransition-[width,height] duration-200plus adelay-*per pseudo-element. The four-stage cascade is now countable. - Tailwind has no per-property delay inside one
transition-*utility, which is the one place this port loses expressiveness — the stagger is approximated by delaying the whole second half. - UI change from the CSS original: brighter accent colours (the originals sat near 3:1 on a near-black ground) and a
focus-visiblering per variant.
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 Animated Border Draw Button with Staged Delays
Source: https://codefronts.com/motion/tailwind-css-animated-buttons/tailwind-animated-border-draw-button/
A border that draws itself around the perimeter on hover, two pseudo-elements sharing the work. The port's real content is timing: before:delay-0, before:transition-[width,height] and a staggered after:delay-[400ms] put the whole four-stage cascade in the class list instead of a comment.
## HTML
```html
<section class="tab-04 w-full min-h-svh grid place-items-center bg-tab04-bg font-tab04-sans px-6 py-10">
<div class="flex flex-col items-center gap-10">
<p class="text-[0.78rem] tracking-[0.14em] uppercase text-tab04-indigo/70 m-0">Hover to draw the border</p>
<div class="flex flex-wrap justify-center gap-5">
<button type="button" class="relative min-h-11 px-9 text-[0.95rem] font-bold tracking-[0.04em] text-tab04-indigo bg-transparent cursor-pointer transition-[color,background-color] duration-[400ms] hover:text-white hover:bg-tab04-indigo/12 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tab04-indigo before:content-[''] before:absolute before:top-0 before:left-0 before:size-0 before:border-t-2 before:border-r-2 before:border-tab04-indigo before:pointer-events-none before:transition-[width,height] before:duration-200 after:content-[''] after:absolute after:right-0 after:bottom-0 after:size-0 after:border-b-2 after:border-l-2 after:border-tab04-indigo after:pointer-events-none after:transition-[width,height] after:duration-200 after:delay-[400ms] hover:before:size-full hover:after:size-full motion-reduce:before:size-full motion-reduce:after:size-full motion-reduce:before:transition-none motion-reduce:after:transition-none"><span class="relative z-10">Explore Docs</span></button>
<button type="button" class="relative min-h-11 px-9 text-[0.95rem] font-bold tracking-[0.04em] text-tab04-emerald bg-transparent cursor-pointer transition-[color,background-color] duration-[400ms] hover:text-white hover:bg-tab04-emerald/12 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tab04-emerald before:content-[''] before:absolute before:top-0 before:left-0 before:size-0 before:border-t-2 before:border-r-2 before:border-tab04-emerald before:pointer-events-none before:transition-[width,height] before:duration-200 after:content-[''] after:absolute after:right-0 after:bottom-0 after:size-0 after:border-b-2 after:border-l-2 after:border-tab04-emerald after:pointer-events-none after:transition-[width,height] after:duration-200 after:delay-[400ms] hover:before:size-full hover:after:size-full motion-reduce:before:size-full motion-reduce:after:size-full motion-reduce:before:transition-none motion-reduce:after:transition-none"><span class="relative z-10">Start Building</span></button>
<button type="button" class="relative min-h-11 px-9 text-[0.95rem] font-bold tracking-[0.04em] text-tab04-rose bg-transparent cursor-pointer transition-[color,background-color] duration-[400ms] hover:text-white hover:bg-tab04-rose/12 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tab04-rose before:content-[''] before:absolute before:top-0 before:left-0 before:size-0 before:border-t-2 before:border-r-2 before:border-tab04-rose before:pointer-events-none before:transition-[width,height] before:duration-200 after:content-[''] after:absolute after:right-0 after:bottom-0 after:size-0 after:border-b-2 after:border-l-2 after:border-tab04-rose after:pointer-events-none after:transition-[width,height] after:duration-200 after:delay-[400ms] hover:before:size-full hover:after:size-full motion-reduce:before:size-full motion-reduce:after:size-full motion-reduce:before:transition-none motion-reduce:after:transition-none"><span class="relative z-10">Contact Sales</span></button>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tab04-bg: #09090f;
--color-tab04-bg: oklch(0.1 0.01 275);
--color-tab04-indigo: #818cf8;
--color-tab04-indigo: oklch(0.7 0.14 279);
--color-tab04-emerald: #34d399;
--color-tab04-emerald: oklch(0.78 0.15 165);
--color-tab04-rose: #fb7185;
--color-tab04-rose: oklch(0.71 0.17 13);
--font-tab04-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tab-04 {
width: 100%;
min-height: 100svh;
}
.tab-04 ::selection {
background: var(--color-tab04-indigo);
color: #0b0b12;
}
```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 Animated Border Draw Button with Staged Delays
Source: https://codefronts.com/motion/tailwind-css-animated-buttons/tailwind-animated-border-draw-button/
A border that draws itself around the perimeter on hover, two pseudo-elements sharing the work. The port's real content is timing: before:delay-0, before:transition-[width,height] and a staggered after:delay-[400ms] put the whole four-stage cascade in the class list instead of a comment.
## HTML
```html
<section class="tab-04 w-full min-h-svh grid place-items-center bg-tab04-bg font-tab04-sans px-6 py-10">
<div class="flex flex-col items-center gap-10">
<p class="text-[0.78rem] tracking-[0.14em] uppercase text-tab04-indigo/70 m-0">Hover to draw the border</p>
<div class="flex flex-wrap justify-center gap-5">
<button type="button" class="relative min-h-11 px-9 text-[0.95rem] font-bold tracking-[0.04em] text-tab04-indigo bg-transparent cursor-pointer transition-[color,background-color] duration-[400ms] hover:text-white hover:bg-tab04-indigo/12 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tab04-indigo before:content-[''] before:absolute before:top-0 before:left-0 before:size-0 before:border-t-2 before:border-r-2 before:border-tab04-indigo before:pointer-events-none before:transition-[width,height] before:duration-200 after:content-[''] after:absolute after:right-0 after:bottom-0 after:size-0 after:border-b-2 after:border-l-2 after:border-tab04-indigo after:pointer-events-none after:transition-[width,height] after:duration-200 after:delay-[400ms] hover:before:size-full hover:after:size-full motion-reduce:before:size-full motion-reduce:after:size-full motion-reduce:before:transition-none motion-reduce:after:transition-none"><span class="relative z-10">Explore Docs</span></button>
<button type="button" class="relative min-h-11 px-9 text-[0.95rem] font-bold tracking-[0.04em] text-tab04-emerald bg-transparent cursor-pointer transition-[color,background-color] duration-[400ms] hover:text-white hover:bg-tab04-emerald/12 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tab04-emerald before:content-[''] before:absolute before:top-0 before:left-0 before:size-0 before:border-t-2 before:border-r-2 before:border-tab04-emerald before:pointer-events-none before:transition-[width,height] before:duration-200 after:content-[''] after:absolute after:right-0 after:bottom-0 after:size-0 after:border-b-2 after:border-l-2 after:border-tab04-emerald after:pointer-events-none after:transition-[width,height] after:duration-200 after:delay-[400ms] hover:before:size-full hover:after:size-full motion-reduce:before:size-full motion-reduce:after:size-full motion-reduce:before:transition-none motion-reduce:after:transition-none"><span class="relative z-10">Start Building</span></button>
<button type="button" class="relative min-h-11 px-9 text-[0.95rem] font-bold tracking-[0.04em] text-tab04-rose bg-transparent cursor-pointer transition-[color,background-color] duration-[400ms] hover:text-white hover:bg-tab04-rose/12 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-tab04-rose before:content-[''] before:absolute before:top-0 before:left-0 before:size-0 before:border-t-2 before:border-r-2 before:border-tab04-rose before:pointer-events-none before:transition-[width,height] before:duration-200 after:content-[''] after:absolute after:right-0 after:bottom-0 after:size-0 after:border-b-2 after:border-l-2 after:border-tab04-rose after:pointer-events-none after:transition-[width,height] after:duration-200 after:delay-[400ms] hover:before:size-full hover:after:size-full motion-reduce:before:size-full motion-reduce:after:size-full motion-reduce:before:transition-none motion-reduce:after:transition-none"><span class="relative z-10">Contact Sales</span></button>
</div>
</div>
</section>
```
## CSS
```css
@import "tailwindcss";
@theme {
--color-tab04-bg: #09090f;
--color-tab04-bg: oklch(0.1 0.01 275);
--color-tab04-indigo: #818cf8;
--color-tab04-indigo: oklch(0.7 0.14 279);
--color-tab04-emerald: #34d399;
--color-tab04-emerald: oklch(0.78 0.15 165);
--color-tab04-rose: #fb7185;
--color-tab04-rose: oklch(0.71 0.17 13);
--font-tab04-sans: 'Space Grotesk', system-ui, sans-serif;
}
.tab-04 {
width: 100%;
min-height: 100svh;
}
.tab-04 ::selection {
background: var(--color-tab04-indigo);
color: #0b0b12;
}
```How this works
Each pseudo-element owns two edges. before: carries the top and right borders anchored at the top-left; after: carries the bottom and left anchored at the bottom-right. Both start at before:size-0 and grow to hover:before:size-full.
The cascade is four delays. Width first, then height, with the second pair offset by the duration of the first — expressed as before:transition-[width,height] plus arbitrary delay-[…] values on the properties that must wait. In CSS this lived in a compound transition shorthand that had to be read character by character; as utilities the four stages are four tokens.
Reduced motion shows the destination. motion-reduce: pins both halves to size-full, so the button simply has a full border with no draw — a state, not a slower animation.
Make it yours
- Halve every duration and delay for a snappier draw (
duration-200→duration-100,delay-[400ms]→delay-200). - Thicker stroke:
border-t-2→border-t-[3px]on all four edge utilities. - Reverse direction by swapping which pseudo-element carries which pair of edges.
Gotchas — read before shipping
- This technique animates
widthandheight, which is layout work on the pseudo-element — fine for a button, wasteful in a long scrolling list. - A 1px seam can appear at the corners on high-DPI screens; nudge with
before:-inset-pxif you see it. - Both pseudo-elements need
pointer-events-none, or the growing overlay swallows the click at the exact moment the border completes.
Browser support
| Chrome | Safari | Firefox | Edge |
|---|---|---|---|
| 111+ | 16.4+ | 128+ | 111+ |
Pseudo-element transitions are universally supported; the floor is Tailwind v4's generated sheet.