webdevpuneet.com

Bootstrap Rate-Limited Action Button — Free HTML CSS JS Snippet

Bootstrap Rate-Limited Action Button · Buttons · Plain HTML, CSS & JS · Live preview

CategoryButtons

Copy & paste

Source Code

<div class="container py-5 d-flex justify-content-center">
  <div class="card bsrate-card">
    <div class="card-body p-4">
      <label class="form-label small fw-semibold">Invite a teammate</label>
      <div class="input-group mb-2">
        <input type="email" class="form-control" id="bsrateEmail" placeholder="[email protected]">
        <button type="button" class="btn btn-dark fw-bold" id="bsrateBtn">Send invite</button>
      </div>
      <p class="small text-muted mb-0" id="bsrateStatus">You can send up to 3 invites per minute.</p>
    </div>
  </div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

A genuine sliding-window rate limiter — the first several clicks are instant, unlike a flat per-click cooldown
One msUntilNextSlot() function is the single source of truth for both blocking clicks and the countdown display
The countdown re-derives remaining time from real timestamps every tick, staying accurate through timer throttling
An empty/invalid input is rejected without consuming one of the limited send slots
The button automatically re-enables itself the instant a slot frees up, with no manual reset needed

About this UI Snippet

Bootstrap Rate-Limited Action Button — HTML, CSS & JavaScript

Screenshot of the Bootstrap Rate-Limited Action Button snippet rendered live

This models a genuinely different, more realistic pattern than a flat "disable for N seconds after every click" cooldown — sentAt records the timestamp of every recent click, and prune() discards any older than the sliding window before every check, so the button only ever blocks once LIMIT clicks have genuinely happened within that window. The first few clicks in a row fire instantly, one after another, exactly like a real API token-bucket or sliding-window rate limiter behaves — not like a resend-code button that always makes you wait the same fixed delay even for your very first click.

msUntilNextSlot() is the one function both the click handler and the countdown display read from — it returns 0 when there's room under the limit, or the exact number of milliseconds until the oldest recorded click ages out of the window and frees up a slot. Because both places call the same function, the button's disabled state and the countdown number it displays can never disagree about how long is actually left.

The countdown ticks every 250ms rather than a full second, re-deriving the remaining time from msUntilNextSlot() on every tick instead of counting down a separately stored number — which is what keeps the displayed countdown accurate even if the tab was backgrounded and timers were throttled, since it's always computed fresh from real timestamps rather than decremented blindly.

Step by step

How to Use

  1. 1
    Type an email and click "Send invite" three times in a row quicklyAll three sends go through instantly, one after another, with no waiting.
  2. 2
    Try clicking a fourth time immediatelyThe button disables and shows a live "Wait Ns" countdown instead of sending.
  3. 3
    Watch the countdownIt ticks down in real time until the oldest of your three sends ages out of the window.
  4. 4
    Wait for the countdown to reach zeroThe button re-enables itself automatically, ready for another send.
  5. 5
    Click "Send invite" with the email field emptyIt shows a validation message instead of counting toward the rate limit at all.

Real-world uses

Common Use Cases

Invite, resend, and notification-sending buttons
Prevents accidental spam-clicking from firing dozens of emails or notifications in a burst.
Any UI action backed by a rate-limited API endpoint
Mirrors the real backend limit in the UI itself, so a user sees the constraint before hitting an API error.
Comment, like, or vote buttons needing abuse prevention
A lightweight client-side deterrent against rapid repeated actions, alongside real server-side rate limiting.

Got questions?

Frequently Asked Questions

A flat cooldown blocks every single click equally, even the very first one in a session. This sliding-window approach allows a genuine burst of clicks up to the limit before blocking anything, only kicking in once that limit is actually exceeded — much closer to how real API rate limits (and their 429 responses) typically behave.

A plain decrementing counter can drift if the browser throttles background tab timers; recomputing msUntilNextSlot() from real Date.now() timestamps on every tick keeps the displayed countdown accurate regardless of any timer throttling that occurred in between.

No — the empty-email check happens before msUntilNextSlot() is even consulted for blocking, and a rejected empty submission never gets pushed into sentAt, so it doesn't consume one of the limited slots.

Yes. Keep sentAt in a ref (not state, since it updates on a timer without needing a full re-render for every millisecond) and mirror the computed disabled/label values into component state on each tick, the same way this snippet updates the DOM directly.