Toaster
Brief, non-blocking messages about the result of an action, raised with toast() from sonner.
@zenoxai/ui/components/sonner Markdown<>
<Toaster />
<Button
variant="outline"
onClick={() => toast.success("Report exported")}
>
Export report
</Button>
</>Usage
Mount Toaster once, near the root of the app, next to any other app-wide hosts:
import { Toaster } from "@zenoxai/ui/components/sonner"
export function App() {
return (
<>
<Routes />
<Toaster />
</>
)
}
Then raise toasts from anywhere, including outside React components, with toast from
sonner:
import { toast } from "sonner"
toast.success("Report exported")
toast.error("Could not reach the SIEM connector")
The examples on this page share the single Toaster rendered by the first example, the same way
an app shares the one at its root. Never mount a second one: each Toaster shows every toast,
so two would show them twice.
Toaster wraps sonner’s component with the Zenox defaults: toasts stack in the top-right
corner, use the popover surface and border tokens, show the library’s status icons, and follow
the .dark class on <html>, so no theme provider is needed. It accepts every
sonner Toaster prop to change the position, the
duration or the number of visible toasts.
Use a toast to confirm that something happened, or failed, without stopping the user: “Report exported”, “Alert assigned”. Write it in the past tense, in one line.
- For a message that must stay on screen until the user deals with it, use an Alert in the page.
- For a decision before an action runs, use an Alert Dialog.
- For an error in a form field, show it under the field.
Examples
Types
toast(), toast.success(), toast.info(), toast.warning() and toast.error() set the icon.
Reserve error for failures the user should act on.
<>
<Button variant="outline" onClick={() => toast("Filter saved")}>
Default
</Button>
<Button
variant="outline"
onClick={() => toast.success("Alert assigned to Marina Santos")}
>
Success
</Button>
<Button
variant="outline"
onClick={() => toast.info("Scan queued behind 2 other scans")}
>
Info
</Button>
<Button
variant="outline"
onClick={() => toast.warning("API key expires in 3 days")}
>
Warning
</Button>
<Button
variant="outline"
onClick={() => toast.error("Could not reach the SIEM connector")}
>
Error
</Button>
</>Status colors
toast.success(), toast.info(), toast.warning() and toast.error() take the soft fill,
border and text of the Alert of the same tone, and the icon repeats the
type, so the status never rests on color alone. A plain toast() stays on the neutral surface.
Set richColors={false} on Toaster only if a product needs every toast neutral.
<>
<Button
variant="outline"
onClick={() =>
toast.success("Host isolated", {
description: "ws-finance-07 can reach only the Zenox agent.",
})
}
>
Success
</Button>
<Button
variant="outline"
onClick={() =>
toast.error("Isolation failed", {
description: "The agent on ws-finance-07 did not respond.",
})
}
>
Error
</Button>
</>With a description
description adds a second line with the detail: which asset, how many records.
<Button
variant="outline"
onClick={() =>
toast.success("Vulnerability scan finished", {
description: "srv-db-01.prod: 2 critical, 5 high, 14 medium.",
})
}
>
Finish scan
</Button>With an action
action adds a button to the toast. Use it for “Undo” after a reversible bulk action, instead of
asking for confirmation first.
<Button
variant="outline"
onClick={() =>
toast("12 alerts archived", {
action: {
label: "Undo",
onClick: () => toast("Alerts restored"),
},
})
}
>
Archive alerts
</Button>Promise
toast.promise() shows a loading toast while a promise runs and replaces it with the success or
error message when it settles.
function ToasterPromise() {
function exportCsv() {
// Stands in for the request that builds the export.
const request = new Promise<{ rows: number }>((resolve) =>
setTimeout(() => resolve({ rows: 1284 }), 2000)
)
toast.promise(request, {
loading: "Exporting alerts",
success: (data) => `Exported ${data.rows} alerts`,
error: "Export failed",
})
}
return (
<Button variant="outline" onClick={exportCsv}>
Export CSV
</Button>
)
}Accessibility
- Toasts are announced by screen readers through a live region and do not take focus.
- A toast closes on its own after a few seconds and pauses while the pointer is over it. Do not put the only path to an action in a toast: an “Undo” button must have an equivalent elsewhere, such as the archive.
- Alt+T moves focus to the toasts, so keyboard users can reach an action button.
API reference
Generated from the TypeScript source. className, style and children are accepted everywhere and omitted below.
Toaster
Toaster renders the toasts raised with `toast()` from "sonner": brief feedback after an action, such as "Saved" or "Export failed", that goes away on its own. Mount it once near the root of the app. For a message that must stay on the page, use Alert.
No props of its own. Accepts the props of the element it renders.