Toast component
Toast is a provider-based notification system: mount ToastProvider once near the root of your app, then call the imperative toast(...) function from anywhere — a click handler, a data-fetching hook, deep inside a component tree — without threading state or props down to get there. It supports a promise-aware mode that walks a toast through loading → success/error automatically.
Playground
Change a prop on the right and the preview updates. Switch to Code to copy what you see.
Recipes
Copy-paste patterns for the ways Toast actually gets used — each one a real, self-contained example.
Typed shortcuts
toast.success / error / warning / info set the type and matching icon. Mount ToastProvider once near your app root; call toast() from anywhere.
// app root
<ToastProvider>
<App />
</ToastProvider>
// anywhere
import { toast } from "oks-ui/toast";
toast.success("Saved");
toast.error("Upload failed");
toast.warning("Storage almost full");
toast.info("A new version is available");Title and description
Pass a description for a second line of context beneath the title.
toast.success("Profile updated", {
description: "Your changes are visible to your team.",
});Toast with an action
An action button turns a notification into something the user can act on — an undo, a reload. Pair it with duration: null so it waits.
toast("Message archived", {
action: { label: "Undo", onClick: () => restore() },
duration: null,
});Promise-aware
Hand toast.promise a promise and it walks loading → success/error on its own, so the loading state can't drift from the real request.
toast.promise(saveProfile(data), {
loading: { message: "Saving…" },
success: () => ({ message: "Profile saved" }),
error: () => ({ message: "Couldn't save profile" }),
});Persistent until dismissed
persistent removes the auto-dismiss timer — pair with dismissible so the user still has a way to close it. Reserve it for things they must act on.
toast.error("Payment failed", {
description: "Update your card to keep your subscription.",
persistent: true,
dismissible: true,
});One provider, called from anywhere
Mount ToastProvider once, high in the tree — it renders a portaled region (position defaults to bottom-right) that every toast() call anywhere in the app renders into. There's no toast context to consume and no hook to call at the use-site; toast(...) is a plain imported function.
// app root
<ToastProvider position="top-right" maxVisibleToasts={3}>
<App />
</ToastProvider>
// anywhere else in the tree
import { toast } from "oks-ui";
const SaveButton = () => {
return (
<Button onPress={() => toast.success("Saved", { description: "Your changes were saved." })}>
Save
</Button>
);
};Typed shortcuts and full control
toast.success/toast.error/toast.warning/toast.info are shortcuts that set both type and the matching default icon. For anything not covered by a shortcut, call toast(options) directly with the full ToastOptions shape — variant, size, duration, a dismiss/action button, whatever you need.
toast.success("Copied to clipboard");
toast.error("Upload failed", { description: "The file exceeded 10 MB.", persistent: true });
toast({
title: "Update available",
description: "A new version is ready to install.",
action: { label: "Reload", onClick: () => window.location.reload() },
duration: null,
});Promise-aware toasts
Pass a promise and toast walks through loading → success/error on its own — no manual success()/error() calls to keep in sync with the actual request. It shows a loading state immediately, then swaps to success or error once the promise settles.
toast.promise(saveProfile(formData), {
loading: "Saving…",
success: "Profile saved",
error: "Couldn't save profile",
});Duration, persistence, and dismissal
Every toast auto-dismisses after defaultDuration (6s) unless you override duration per-toast, or set persistent to remove the auto-dismiss timer entirely (typically paired with dismissible so the user still has a way to close it manually). showDurationBar renders a shrinking progress bar so the countdown is visible, not just implied.
toast.warning("Session expiring soon", { duration: 10000, showDurationBar: true });
toast.error("Payment failed", { persistent: true, dismissible: true });Props
The full public API for Toast. Every prop is stable and intentionally typed.
Provider — Content
| Prop | Type | Default | Description |
|---|---|---|---|
| children | ReactNode | — | Your app, rendered inside the provider. |
children
ReactNode
default: —
Your app, rendered inside the provider.
Provider — Layout & positioning
| Prop | Type | Default | Description |
|---|---|---|---|
| position | "top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right" | "bottom-right" | Where the toast region renders. |
| maxToasts | number | 12 | Total toasts kept in the queue (visible + pending). |
| maxVisibleToasts | number | 3 | Toasts shown at once before stacking/queuing. |
| toastOffset | number | 0 | Extra offset from the viewport edge. |
| container | Element | DocumentFragment | null | — | Custom portal mount target. |
position
"top-left" | "top-center" | "top-right" | "bottom-left" | "bottom-center" | "bottom-right"
default: "bottom-right"
Where the toast region renders.
maxToasts
number
default: 12
Total toasts kept in the queue (visible + pending).
maxVisibleToasts
number
default: 3
Toasts shown at once before stacking/queuing.
toastOffset
number
default: 0
Extra offset from the viewport edge.
container
Element | DocumentFragment | null
default: —
Custom portal mount target.
Provider — Behavior & states
| Prop | Type | Default | Description |
|---|---|---|---|
| defaultDuration | number | 6000 | Auto-dismiss duration in ms, unless overridden per-toast or persistent. |
| toastProps | ToastOptions | — | Default options applied to every toast from this provider. |
defaultDuration
number
default: 6000
Auto-dismiss duration in ms, unless overridden per-toast or persistent.
toastProps
ToastOptions
default: —
Default options applied to every toast from this provider.
Provider — Motion
| Prop | Type | Default | Description |
|---|---|---|---|
| motion | "auto" | "reduced" | "default" | "auto" | Animation mode; "auto" respects prefers-reduced-motion. |
| disableAnimation | boolean | false | Disables all toast animation. |
motion
"auto" | "reduced" | "default"
default: "auto"
Animation mode; "auto" respects prefers-reduced-motion.
disableAnimation
boolean
default: false
Disables all toast animation.
Provider — Styling
| Prop | Type | Default | Description |
|---|---|---|---|
| regionProps | ToastRegionProps | — | Extra props for the toast region container. |
| className | string | — | Class applied to the toast region. |
| style | CSSProperties | — | Inline styles for the toast region. |
regionProps
ToastRegionProps
default: —
Extra props for the toast region container.
className
string
default: —
Class applied to the toast region.
style
CSSProperties
default: —
Inline styles for the toast region.
Toast — Content
| Prop | Type | Default | Description |
|---|---|---|---|
| title | ReactNode | — | Toast title. |
| description / message | ReactNode | — | Toast body content. |
| icon | ReactNode | — | Overrides the default type-derived icon. |
| showIcon / hideIcon | boolean | shown | Show or hide the icon slot; hideIcon wins when both are set. The icon is shown by default and re-evaluated when type or color changes. |
| loadingComponent | ReactNode | — | Shown in the icon slot while type is "loading" (for example during a promise toast), instead of the status icon. |
| endContent | ReactNode | — | Content rendered at the end of the toast. |
| action | { label: string; onClick?: () => void } | — | An inline action button. |
title
ReactNode
default: —
Toast title.
description / message
ReactNode
default: —
Toast body content.
icon
ReactNode
default: —
Overrides the default type-derived icon.
showIcon / hideIcon
boolean
default: shown
Show or hide the icon slot; hideIcon wins when both are set. The icon is shown by default and re-evaluated when type or color changes.
loadingComponent
ReactNode
default: —
Shown in the icon slot while type is "loading" (for example during a promise toast), instead of the status icon.
endContent
ReactNode
default: —
Content rendered at the end of the toast.
action
{ label: string; onClick?: () => void }
default: —
An inline action button.
Toast — Appearance
| Prop | Type | Default | Description |
|---|---|---|---|
| type | "default" | "info" | "success" | "warning" | "error" | "loading" | derived from color, else "default" | Semantic type, also picks the default icon. |
| color | ToastColor | — | Semantic color. |
| variant | "solid" | "soft" | "flat" | "bordered" | "flat" | Visual style variant. |
| radius | OksRadius | "md" | Border radius. |
| size | OksSize | "md" | Toast size. |
type
"default" | "info" | "success" | "warning" | "error" | "loading"
default: derived from color, else "default"
Semantic type, also picks the default icon.
color
ToastColor
default: —
Semantic color.
variant
"solid" | "soft" | "flat" | "bordered"
default: "flat"
Visual style variant.
radius
OksRadius
default: "md"
Border radius.
size
OksSize
default: "md"
Toast size.
Toast — Layout & positioning
| Prop | Type | Default | Description |
|---|---|---|---|
| position | ToastPosition | provider's position | Per-toast position override. |
position
ToastPosition
default: provider's position
Per-toast position override.
Toast — Behavior & states
| Prop | Type | Default | Description |
|---|---|---|---|
| duration | number | null | 6000 | Auto-dismiss duration in ms; null disables auto-dismiss. |
| persistent | boolean | false | Never auto-dismisses. |
| showDurationBar | boolean | false | Shows a countdown progress bar. |
| dismissible | boolean | true | Shows a close button. |
| promise | Promise<unknown> | — | Drives the promise-aware loading/success/error flow. |
duration
number | null
default: 6000
Auto-dismiss duration in ms; null disables auto-dismiss.
persistent
boolean
default: false
Never auto-dismisses.
showDurationBar
boolean
default: false
Shows a countdown progress bar.
dismissible
boolean
default: true
Shows a close button.
promise
Promise<unknown>
default: —
Drives the promise-aware loading/success/error flow.
Toast — Events
| Prop | Type | Default | Description |
|---|---|---|---|
| onDismiss | (id: ToastId) => void | — | Called when the toast is dismissed. |
onDismiss
(id: ToastId) => void
default: —
Called when the toast is dismissed.
Toast — Styling
| Prop | Type | Default | Description |
|---|---|---|---|
| closeIcon | ReactNode | — | Overrides the default close icon. |
| classNames | ToastClassNames | — | Per-slot class overrides. |
| className | string | — | Class applied to this toast's root element. |
closeIcon
ReactNode
default: —
Overrides the default close icon.
classNames
ToastClassNames
default: —
Per-slot class overrides.
className
string
default: —
Class applied to this toast's root element.
Accessibility
- The toast region is a live region, so screen readers announce new toasts as they appear without the user needing to navigate to them.
- When dismissible (the default), the close button is a real, keyboard-operable button with its own accessible name.
- Prefer persistent + a visible action for anything the user actually needs to act on — an auto-dismissing toast that disappears before it's read defeats its own purpose for anyone reading slowly or using a screen reader.
Best practices
- Keep toast text to one short sentence; if a message needs a paragraph of explanation, it probably belongs in an inline Alert instead.
- Reserve persistent for toasts the user must act on (a failed payment, a required re-auth) — persistent success confirmations just pile up.
- Use toast.promise for anything already returning a promise (a save, an upload, a fetch) instead of manually calling toast.success/toast.error in a .then()/.catch() — it keeps the loading state honest.
- Only one ToastProvider is meant to be mounted per toast "queue" — nesting multiple providers doesn't give you independent queues, since toast() targets whichever provider is currently mounted.
- For a message tied to specific content on the page (a form field error, a section-level warning), use Alert instead — Toast is for transient, page-level notifications, not content that should stay anchored in the layout.