SolutionsCase StudiesAI ToolsResourcesAboutContact
Get Your Free AI Automation Audit Book a Free 30-Minute Strategy Call
Playground~/frontend Open editor

~/css/tailwind-animated-buttons

6 Tailwind Animated Buttons

3 Tailwind3 with JSPublished 2026-10-05Free · no sign-up

Six buttons that move with purpose: a save button with a spinner, a bell with a pinging badge, a pulsing call to action, a bouncing scroll-down arrow, a heart that pops when liked and a download button that fills as it progresses.

01. Tailwind Loading Button with Spinner

TailwindButtonLoading

Click and the button shows an animate-spin spinner with Saving… and becomes busy for two seconds. aria-busy and the disabled state stop double submits, and the spinner is drawn with a border trick, no image needed.

View code
<button id="twab1" type="button" class="inline-flex items-center gap-2 rounded-lg bg-indigo-600 px-5 py-2.5 font-semibold text-white hover:bg-indigo-700 disabled:cursor-wait disabled:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">
  <span aria-hidden="true" class="hidden size-4 animate-spin rounded-full border-2 border-white/40 border-t-white motion-reduce:animate-[spin_1.5s_linear_infinite]"></span>
  <span>Save draft</span>
</button>
var b = document.getElementById('twab1'), sp = b.children[0], tx = b.children[1];
b.onclick = function () { b.disabled = true; b.setAttribute('aria-busy', 'true'); sp.classList.remove('hidden'); tx.textContent = 'Saving…'; setTimeout(function () { b.disabled = false; b.removeAttribute('aria-busy'); sp.classList.add('hidden'); tx.textContent = 'Saved'; b.focus(); }, 2000); };

02. Tailwind Notification Bell with Ping

TailwindButtonBadge

A bell button with a red dot that sends out a ping ring using animate-ping, a quiet way to say there is something new. The count is in the accessible name, and the ring is skipped for reduced motion.

View code
<button type="button" aria-label="Notifications, 3 unread" class="relative grid size-12 place-items-center rounded-full bg-slate-800 text-slate-100 hover:bg-slate-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-sky-300">
  <svg aria-hidden="true" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="size-6"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.9 1.9 0 0 0 3.4 0"/></svg>
  <span aria-hidden="true" class="absolute right-2.5 top-2.5 flex size-3"><span class="absolute inline-flex size-full animate-ping rounded-full bg-red-400 opacity-75 motion-reduce:hidden"></span><span class="relative inline-flex size-3 rounded-full bg-red-500"></span></span>
</button>

03. Tailwind Pulsing Call-to-Action

TailwindButtonPulse

A pill button with a soft halo pulsing out behind it, for the one action you really want noticed. The halo is a separate animate-ping span under the button, so the text itself never moves.

View code
<div class="relative inline-flex">
  <span aria-hidden="true" class="absolute inset-0 animate-ping rounded-full bg-rose-500/40 [animation-duration:2s] motion-reduce:hidden"></span>
  <a href="#live" class="relative rounded-full bg-rose-600 px-7 py-3 font-bold text-white shadow-lg hover:bg-rose-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-rose-600">Join the live demo</a>
</div>

04. Tailwind Bouncing Scroll Button

TailwindButtonBounce

A scroll-down button for the bottom of a hero section, with an arrow that bounces using animate-bounce. Its label says where it goes, and the bounce stops under prefers-reduced-motion.

View code
<a href="#features" class="group grid justify-items-center gap-2 rounded-xl p-2 text-sm font-semibold text-slate-200 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-slate-200">See the features
  <span aria-hidden="true" class="grid size-11 animate-bounce place-items-center rounded-full border-2 border-slate-400 text-lg group-hover:border-white motion-reduce:animate-none">↓</span>
</a>

05. Tailwind Like Button with Pop

TailwindButtonToggle

A heart toggle that pops and fills red when liked, with a counter beside it. aria-pressed holds the state, the aria-pressed: variant styles it, and a small keyframe gives the pop only when motion is allowed.

View code
<button id="twab5" type="button" aria-pressed="false" class="group inline-flex items-center gap-2 rounded-full border border-slate-300 bg-white px-4 py-2 font-semibold text-slate-700 hover:bg-slate-50 aria-pressed:border-rose-300 aria-pressed:bg-rose-50 aria-pressed:text-rose-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-rose-600">
  <svg aria-hidden="true" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" class="size-5 fill-none group-aria-pressed:fill-rose-600 group-aria-pressed:stroke-rose-600 motion-safe:group-aria-pressed:animate-[twab-pop_.35s_ease-out]"><path d="M12 20s-7-4.4-7-10a4 4 0 0 1 7-2.6A4 4 0 0 1 19 10c0 5.6-7 10-7 10z"/></svg>
  <span>Like</span><span class="tabular-nums" id="twab5c">41</span>
</button>
@keyframes twab-pop { 40% { transform: scale(1.35); } }
var b = document.getElementById('twab5'), c = document.getElementById('twab5c');
b.onclick = function () { var on = b.getAttribute('aria-pressed') !== 'true'; b.setAttribute('aria-pressed', on); c.textContent = on ? 42 : 41; };

06. Tailwind Download Button with Progress

TailwindButtonProgress

A download button that fills with a progress bar from left to right, then reads Downloaded. The fill is a span whose width the script updates; a status region announces the start and the end rather than every percent.

View code
<button id="twab6" type="button" class="relative h-12 w-48 overflow-hidden rounded-xl bg-slate-800 font-semibold text-white hover:bg-slate-700 disabled:cursor-default focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-slate-800">
  <span aria-hidden="true" class="absolute inset-y-0 left-0 w-0 bg-emerald-600 transition-[width] duration-200"></span>
  <span class="relative">Download report</span>
</button>
<p id="twab6s" role="status" class="sr-only"></p>
var b = document.getElementById('twab6'), bar = b.children[0], tx = b.children[1], st = document.getElementById('twab6s');
b.onclick = function () { var p = 0; b.disabled = true; st.textContent = 'Download started'; var t = setInterval(function () { p += 10; bar.style.width = p + '%'; tx.textContent = p + '%'; if (p >= 100) { clearInterval(t); tx.textContent = 'Downloaded'; st.textContent = 'Download complete'; setTimeout(function () { b.disabled = false; bar.style.width = '0'; tx.textContent = 'Download report'; }, 2500); } }, 200); };

About these Tailwind Animated Buttons

Built-in animations

animate-spin, animate-ping, animate-pulse and animate-bounce cover most button motion. Change speed with [animation-duration:2s].

Custom keyframes

For anything else, define keyframes in your CSS or tailwind.config and reference them with animate-[name_.35s_ease-out].

Announce state, not motion

Use aria-busy, aria-pressed and a status region so the change is clear without seeing the animation.

Reduced motion

Decorative motion such as pings and bounces gets motion-reduce:hidden or motion-reduce:animate-none; a spinner can slow down instead, since it carries meaning.

Frequently asked questions

Do these submit real data?

No. The loading and download states are simulated with timers for the demo.

Can I style aria-pressed?

Yes. Tailwind v3.4 has aria-pressed: and group-aria-pressed: variants built in.

Is there a CSS version?

Yes, see the CSS animated buttons collection.