Toast
A succinct message that is displayed temporarily.
import { Button } from '@/components/ui/button';
import { toast, Toaster, ToastProvider } from '@/components/ui/toast';
export default function ToastDemo() {
return (
<ToastProvider>
<Button
variant="outline"
onClick={() =>
toast('Scheduled: Catch up', {
description: 'Friday, February 10 at 5:57 PM',
})
}
>
Show toast
</Button>
<Toaster />
</ToastProvider>
);
}
Install
npx shadcn@latest add @madeui/toast
Usage
import { toast, Toaster, ToastProvider } from '@/components/ui/toast';
// 1. Wrap your app in <ToastProvider> and mount <Toaster /> once (e.g. in the root layout).
// 2. Call `toast` from anywhere — components, event handlers, stores:
toast('Saved', { description: 'Your changes were saved.' });
toast.success('Deployed');
toast.error('Could not save');
Stacking
Toasts pile up behind the newest one (up to the provider’s limit, 3 by
default). Hovering or focusing the stack expands it to show every toast.
Trigger the demo above a few times in a row to see it.
Swipe to dismiss
Drag a toast down or right (touch or mouse) to dismiss it. Configure with
<Toaster swipeDirection={['down', 'right']} /> — any of 'up' | 'down' | 'left' | 'right', or a single value.
Promise
toast.promise shows a loading toast, then updates it in place when the
promise settles.
import { Button } from '@/components/ui/button';
import { toast, Toaster, ToastProvider } from '@/components/ui/toast';
function save() {
return new Promise<void>((resolve) => setTimeout(resolve, 2000));
}
export default function ToastPromise() {
return (
<ToastProvider>
<Button
variant="outline"
onClick={() =>
toast.promise(save(), {
loading: 'Saving…',
success: 'Changes saved',
error: 'Could not save',
})
}
>
Save with toast.promise
</Button>
<Toaster />
</ToastProvider>
);
}
Duration
import { Button } from '@/components/ui/button';
import { Toaster, ToastProvider, useToast } from '@/components/ui/toast';
function DemoButton() {
const toast = useToast();
return (
<Button
variant="outline"
onClick={() =>
toast.add({
title: 'Sticky toast',
description: 'Stays for 10 seconds.',
timeout: 10000,
})
}
>
Show sticky toast
</Button>
);
}
export default function ToastDuration() {
return (
<ToastProvider>
<DemoButton />
<Toaster />
</ToastProvider>
);
}
Types
toast.success and toast.error set a type on the toast (mirrored as
data-type on the rendered element). Styling is identical across types out
of the box — since you own components/ui/toast.tsx, add a [data-type="…"]
condition to styles.root to color-code them.
import * as stylex from '@stylexjs/stylex';
import { Button } from '@/components/ui/button';
import { toast, Toaster, ToastProvider } from '@/components/ui/toast';
import { space } from '@/lib/constants.stylex';
export default function ToastTypes() {
return (
<ToastProvider>
<div {...stylex.props(styles.row)}>
<Button
variant="outline"
onClick={() => toast('Event created', { description: 'Team sync at 3 PM.' })}
>
Default
</Button>
<Button
variant="outline"
onClick={() => toast.success('Changes saved')}
>
Success
</Button>
<Button
variant="outline"
onClick={() => toast.error('Could not save', { description: 'Try again.' })}
>
Error
</Button>
</div>
<Toaster />
</ToastProvider>
);
}
const styles = stylex.create({
row: {
display: 'flex',
flexWrap: 'wrap',
gap: space.s2,
},
});
Action
Pass actionProps to render an action button inside the toast.
import { Button } from '@/components/ui/button';
import { toast, Toaster, ToastProvider } from '@/components/ui/toast';
export default function ToastAction() {
return (
<ToastProvider>
<Button
variant="outline"
onClick={() =>
toast('Message archived', {
actionProps: {
children: 'Undo',
onClick: () => toast('Message restored'),
},
})
}
>
Archive message
</Button>
<Toaster />
</ToastProvider>
);
}
Position
The stack’s screen position lives in Toaster’s own styles; override it with
the style prop, same as any other component in this library.
import * as stylex from '@stylexjs/stylex';
import { Button } from '@/components/ui/button';
import { toast, Toaster, ToastProvider } from '@/components/ui/toast';
import { space } from '@/lib/constants.stylex';
export default function ToastPosition() {
return (
<ToastProvider>
<Button
variant="outline"
onClick={() => toast('Synced to top left')}
>
Show toast
</Button>
<Toaster style={styles.topLeft} />
</ToastProvider>
);
}
const styles = stylex.create({
topLeft: {
bottom: null,
right: null,
left: space.s4,
top: space.s4,
},
});
API reference
Built on Base UI Toast. The tables below cover the props this library adds or changes — every other prop is forwarded to the underlying Base UI part; see the Base UI Toast API reference for the full list.
toast(title, options?)
Imperative API backed by a module-level toast manager — no hook needed, works
outside React. useToast() remains available for the hook form
(useToast().add({ … })).
| Prop | Type | Default | Description |
|---|---|---|---|
title |
ReactNode |
— | Toast heading. |
description |
ReactNode |
— | Supporting text. |
timeout |
number |
— | Auto-dismiss delay in ms (Base UI default: 5000). |
type |
string |
— | Toast type; toast.success / toast.error set it for you. |
actionProps |
object |
— | Props for the action button (e.g. { children: 'Undo', onClick }). |
Also available: toast.promise(promise, { loading, success, error }),
toast.update(id, options), toast.close(id).
Toaster
| Prop | Type | Default | Description |
|---|---|---|---|
swipeDirection |
Direction | Direction[] |
['down', 'right'] |
Direction(s) a toast can be swiped to dismiss. |
Toaster renders the styled toast stack; to change its look, edit components/ui/toast.tsx directly — you own the source.