Skip to content
OTFotf
All posts

shadcn's toast page wants toast.add with a title, not one call

D
DaveAuthor
6 min read
shadcn's toast page wants toast.add with a title, not one call

A success message after a form submit usually looks like one function call. On the shadcn toast page it is toast.add with a title, and the Toaster has to sit in your layout before any message shows.

What the shadcn toast page covers

The page describes the component as "A succinct message that is displayed temporarily." The install command is pnpm dlx shadcn@latest add toast. The setup has two parts. A Toaster goes once in app/layout.tsx, and a toast function is imported from the same @/components/ui/toast path wherever you need a message.

The usage example calls toast.add with a title and a description. An action, such as an undo button, goes in an actionProps object, and toast.close takes the id that toast.add returns. The page also has a Types section that describes a type option and a Promise demo. Both of their code blocks are collapsed on the page, so check the View Code panel before you rely on either one.

The page does not say Toast is deprecated, does not mention Sonner, and does not recommend another library. It has no sentence about when to use a toast. The rules below are ours, and they are labelled as ours.

Mount the Toaster once

The Toaster renders the stack of messages. Put it in the root layout, inside the body and after your page content, so every route can show a message. Mounting it in a single page means a message fired from another page will not appear.

import { Toaster } from "@/components/ui/toast"

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>
        <main>{children}</main>
        <Toaster />
      </body>
    </html>
  )
}

11 production screens. Login and database wired.

The SaaS Dashboard Kit includes login, a database, and a working dashboard. Live demo at saas.otf-kit.dev.

See the live demo

Show success or error after a submit

The common case is a form that either saves or fails. Call toast.add in both branches, so the user always gets a result. The success message states what happened. The error message states what failed and gives the user something to do next.

"use client"

import { Button } from "@/components/ui/button"
import { toast } from "@/components/ui/toast"

export function ProfileForm() {
  async function onSave() {
    try {
      await saveProfile() // your save call
      toast.add({
        title: "Profile saved",
        description: "Your changes are live.",
      })
    } catch {
      toast.add({
        title: "Could not save",
        description: "Check your connection and try again.",
      })
    }
  }

  return <Button onClick={onSave}>Save profile</Button>
}

Keep the form's input when the save fails. A message that says "could not save" while the form clears has taken the user's work with it. Clear the form only after the success branch runs.

Luna presses a submit button while a success card appears beside her

Offer an undo

Some actions can be reversed, such as archiving a project. The toast can carry a single action. The page's example passes an actionProps object with the button label as children and an onClick handler. Keep the id that toast.add returns, and close the toast from inside the handler after the reversal:

const id = toast.add({
  title: "Project archived",
  actionProps: {
    children: "Undo",
    onClick() {
      restoreProject() // your restore call
      toast.close(id)
    },
  },
})

Only offer an action the user can actually reverse. If the action cannot be undone, put the warning in a dialog before the change, not in a toast after it.

Write the wording

Our rule for the copy is short. The title states the result in a few words. The description states the next step, or says nothing when the title is enough. Avoid vague titles such as "Done" or "Error", because the user cannot tell what changed.

Length matters more than most teams expect. A title of a few words reads in one glance. A title of twenty words wraps on a phone and pushes the description below the fold. Keep titles short and move detail into the description. If a message needs three sentences, it is probably a dialog or a line on the page, not a toast.

Say what happened in plain words. "Profile saved" states a result. "Success!" adds nothing, and the exclamation mark makes a routine save sound like an event. Avoid stacking the same error on every retry. Let the user act on the first message before you add another one.

Before you use the type option for success and error styling, read its code on the page. The code is collapsed, so the example you can see does not show it. Until you have checked it, the title and description carry the meaning on their own.

Dex and Luna watching a check card leave at the screen edge

Test before you ship

Toasts fail where the network, the screen size and the keyboard meet. Check these before you ship:

  • Turn the network off and submit. The error toast should show, and the form should keep the user's input.
  • Submit twice quickly. The success toast should show once for one save, and the button should not allow a second submit while the first is running.
  • Submit several times in a row. Toasts stack, so check that the stack does not cover the submit button on a 390px phone.
  • Tab to the undo action after the toast appears. It should take focus, and pressing Enter should run the reversal.
  • Wait for the toast to leave. Anything the user needs later should be on the page, not only in the toast, because the toast is temporary by design.

Run the phone check last, after the wording is final. Long titles wrap, and a wrapped message can push the stack over the page.

Where OTF stands

If you want a toast or a notification component already built into a product, we cannot point you to one. We checked the SaaS Dashboard, Booking, Fitness and Arcade kit pages for toast, notification and alert terms. None of them names a toast component. The SaaS Dashboard page lists "Inbox & notifications" as a feature. That is a feature of the product, not a toast component, and this article does not claim it is one.

The pricing page lists the Full-stack kits at $99 each and the Everything Bundle at $149, both as one-time payments, and it offers a live demo before you buy. Check each kit's repository for the components it ships before you rely on any of them. For the forms that use these messages, see the dialog and sheet guide, and for the table actions that often need a result message, see the data table guide. If you are choosing a starting point for a product, the pricing page is the place to compare kits side by side: OTF pricing.

Sources

design-systemtemplates
OTF SaaS Dashboard Kit

Ship the product, not the setup.

  • 11 production screens — auth, team, analytics, and settings
  • Login and a real database are wired in
  • AI configs pre-tuned so your agent extends instead of regenerates
Need more than components?

Full-stack kits.
Pay once, own the code.

SaaS Dashboard and Fitness include authentication and a database. Arcade is browse-first with a local demo session and no backend sign-in by default. Booking is in Preview; Marketplace is coming soon and not currently sold. The Bundle includes the three live kits.

Everything Bundle — $149See full pricing

Get the free AI configs pack

Pre-tuned AI configs for Cursor, Claude, and Lovable — drop them in and your AI tool instantly understands your project.

No spam. Unsubscribe any time.

Prefer the free SDK? Star it on GitHub →