Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Rate Limit Dialog Block for React

An API console with its 429 notice shown open: a dialog with the quota used, the plan's limit, a clock to the reset and a Countdown Button that turns into Retry request when the wait ends.

Framework
UI library

Preview

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Overview

Tell someone how long to wait, and let them retry the moment they can, with this rate-limit dialog for React with Base UI. It opens from the API console of Spillway, an API platform: the header holds an outline Send request Button, and the console, a request bar and a log of the latest calls with the refused one first, is drawn under a soft scrim inside a hairline frame with a plus mark on each corner. The Dialog lists the 429 status, the time until the window resets from the Timer, what was used as a full Progress bar (1,000 of 1,000 requests this minute) and the plan's limit, with a link to raise it. Its action is the catalog Countdown Button: it reads "Wait 41s" while a fill drains behind it, and at zero it becomes an ordinary Retry request. The wait is a typed 42 seconds and is bounded: the clock speaks when it starts, at 30 and 10 seconds, and when you can retry, never every second. For preview the dialog is drawn open in place when the page loads, its clock stopped at 0:42; Send request opens the real Dialog, where the clock runs. For APIs, exports, imports and any limit that resets.

FAQ

Why is the dialog already open, and why is the clock stopped?

So you can see it without a click, and so a poster or a gallery card never ages. On load the dialog is a copy drawn in place over the console: a native dialog element that isn't modal, so nothing is trapped, hidden or focused. In it the clock stands still at 0:42 and the button reads "Wait 42s" with its fill full. Send request in the header opens the real Dialog, modal, with its focus trap and Escape, and there both clocks run. Both wrappers share LimitFields and the block's state. In your app keep the Dialog and drop the copy.

What are the two clocks, and can they disagree?

The reading "Resets in 0:42" is set by the ticks of the catalog Timer, kept out of sight, which counts the typed 42 seconds; the Countdown Button counts the same 42 seconds on its own, with a CSS fill that is the real clock of its label and a digit that ticks once a second. They start together and end within a frame of each other, and whichever finishes first turns the button into Retry request and says "You can retry now". In your app start both from the server's Retry-After header instead of a typed number.

What does a screen reader hear?

The status line inside the dialog says when the clock starts ("Resets in 42 seconds"), at 30 and at 10 seconds, and when you can retry. It never speaks every second. The visible clock is plain text, and the button's own polite status reads its waiting label once. The progress bar is decorative: the same fact is in the sentence next to it. A modal hides the page's own status message, which is why the dialog carries a second one.

What does Retry request do here, and how do I wire it up?

Nothing is requested. Once the wait is over, pressing it closes the dialog, adds a 200 OK row at the top of the drawn console and says so in a polite status message; before then the button holds its presses and keeps focus, and its label and the clock say how long is left. In your app resend the request in retry, keep the dialog open with a busy state until the response arrives, and if you get another 429 restart the clock from the new Retry-After.

Where does focus go, and how does it close?

The real dialog opens with focus on Retry request. While the wait runs that button is still focusable, so a keyboard user stays on it and hears its waiting label, but pressing it does nothing until the clock ends; then the same press retries. Escape, Close and the corner button close the dialog and return focus to Send request. Retry request is the focus target through initialFocus. The clock stops when the dialog closes and starts again, from 42, when it opens. The copy shown on load moves no focus; Escape inside it closes it the same way.

How does it look on a phone?

The copy shown on load docks to the foot of the page as a bottom sheet with its buttons pinned, Retry request above and Close under it, and the list scrolling above them. The status and the clock come first in the list so they stay in view. The real dialog keeps the Dialog's own phone layout, sticking to the bottom edge.

  • Pro

    Two Actions Dialog

    Confirm and consent

    A mail client with its sent confirmation shown open: a dialog with a View message button and an Undo whose label counts down from 10 while a fill drains, with Return to drafts staying on the page.

  • Pro

    Session Timeout Dialog

    Status and errors

    A bank's accounts page with an alert dialog shown open that warns before an idle session ends: a one-minute clock with a draining bar, Stay signed in and Sign out now, and a signed-out view at zero.

  • Pro

    Warning Dialog

    Destructive confirms

    A hosted database's Migrations page with its caution shown open: an alert dialog with a drawn freeze track and a checkbox that must be ticked before the destructive Run anyway turns on.

  • Pro

    Success Dialog

    Status and errors

    An invoice page with its payment confirmation shown open: a dialog with a drawn check, a receipt list with a copy button for the reference, and one button that settles the invoice.

  • Pro

    Loading Dialog

    Status and errors

    A release tool's page with its publish alert shown open: a four-step run that starts when you press the button, never moves the dialog while it waits, shows skeleton boxes where the file sizes will be, and can be stopped.

  • Pro

    Confirm Delete Dialog

    Destructive confirms

    A planner's project list with its delete confirmation shown open: an alert dialog that lists what goes with the project, asks for its name to be typed exactly, and keeps Delete off until it matches.