Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Loading Toast Notification Block for React

A file transfer app's folder with an Upload button: one toast follows the run, a spinner and 1 of 3 uploaded with a Cancel while it runs, then the same toast becomes 3 files uploaded with an Open folder, or Upload cancelled.

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

Keep one toast honest from the start of a job to its end, with this loading toast for React with Base UI. It's the Autumn menus folder of Dropwell, a file transfer app, drawn in a hairline frame with a plus mark on each corner: a top bar with a Cancel Button and the Upload 3 files Shine Button, a list of three files with their sizes and a word each (Waiting, Uploading, Uploaded) and an overall bar that matches "1 of 3 uploaded". Pressing Upload starts a run of three timeouts, 1.2 seconds apart, and raises one toast, wearing the look of the catalog's Toast: a spinner, "Uploading 3 files", "0 of 3 uploaded." and a Cancel. The same toast then updates in place at each step and, at the end, becomes "3 files uploaded" with an Open folder; Cancel stops the run where it is and the toast says how many files were kept. Cancel is also on the page, so closing the toast doesn't take the control away. On load the upload has finished and its toast is drawn in place; Upload raises a real one at the end of the screen. It's built from Toast, Button, Shine Button and Guides, with CSS motion only. For uploads, exports, imports and any job with steps.

FAQ

Why does it open with a finished upload, and what do I keep?

So the preview shows a toast without a job running behind it: nothing here may loop or start by itself, so on load the three files are up and the toast "3 files uploaded" is drawn in place at the stage's foot end, using the catalog toast's own classes. Upload 3 files starts a run and raises a real toast; the drawn one stays gone until a reload. In your app keep the toaster, raise and apply, and drop the drawn copy: the "in-place" state, DrawnToast and the ol in the frame.

How does one toast change from loading to done?

The block makes its own manager with createToaster() (Base UI's createToastManager), renders <Toaster toaster={toaster} /> once, and raises the toast with toaster.add({ id, type: "loading", title, description, actionProps: { children: "Cancel", onClick }, timeout: 0 }). Adding again with the same id and type: "success" updates that toast in place; a timeout of 0 keeps it up.The block describes the run in one function, noteOf, and calls apply after every step, so the toast and the page can't disagree. For one call that follows a promise, see the promise toast.

What does the run do, and how do I wire it up?

Three timeouts, started by the button and stored in a ref, 1.2 seconds apart: each counts one more file as uploaded. Cancel clears the ones that haven't fired, so the run stops where it is, and so does the block leaving the page. Nothing is uploaded and nothing leaves the tab: the run only counts. In your app start the transfer in start, call finish from its progress events, and call cancel to abort it.

What if the toast is closed during the run?

It stays closed: the block hears that the toast started to leave (onClose) and doesn't raise it again at the next step, so a toast you dismissed doesn't come back. The page keeps the run's state, Cancel stays on it, and a polite status message says each step and the result instead.

Is it accessible?

The real toast lives in a live region that speaks it, and updating it in place speaks the new text. Its spinner stops under reduced motion, its Cancel and Open folder are buttons, and the toast stays until it is closed or the next run replaces it, since it carries an action. The files are a list named "Files" and each says its state in words; the bar is decorative and the count is written beside it. The drawn copy is a list named "Notifications".

How does it look on a phone?

The two buttons sit side by side in the top bar, the file names truncate and keep their status, and the drawn toast takes the width of the page minus a margin at the foot. The real toast is the library's own: full width at the end of the screen.

  • Pro

    An invoicing app's invoice with a Send button: one toast follows the request through the toaster's own promise call, Sending, then Invoice sent or Couldn't send with a Retry that succeeds, and a toggle group chooses how the next request ends.

  • Pro

    The settings page of a form builder with its Save settings button: two success toasts are drawn on the page, and pressing Save raises a real toast through the block's own toaster, stacking up to three.

  • Pro

    A messaging app's thread with a message toast that carries a Reply action: it never times out, Reply takes it away and puts the sender in the composer with focus, and Receive a message raises the next of three, up to three at once.

  • Pro

    A finished bulk import as a two-part result bar with counts, a collapsible table of the sixteen rows that failed, and a real CSV error report you can download.

  • Pro

    Three synced objects (Contacts, Deals, Invoices) with a progress bar, a count that rolls, an errors button that opens a popover of the failing records, and a Sync now per row that runs three typed steps.

  • Pro

    An invoicing app's list with a delete on every row: the toast says how many are deleted with an Undo, a second delete merges into the same toast and starts its wait again, and Restore deleted on the page does the same as Undo.