XDSToast@xds/core · Toast

Usage

Toast shows a brief, non-blocking notification to confirm an action or present temporary information. Use it for scenarios where the user needs feedback but not a decision, such as saving, deleting, or changing a status. For production use, prefer the `useXDSToast()` hook — it handles positioning, stacking, auto-dismiss, and deduplication via `XDSToastViewport`. The `XDSToast` component renders the visual toast element inline and is useful for previews, documentation, and static showcases where the viewport lifecycle is not needed.

Best practices

GuidancePractices
DoKeep messages short - only a few words that tell the user what happened, like "Changes saved" or "Message sent".
DoAdd an undo action in the endContent slot for reversible operations like deleting an item, so the user can recover without navigating away.
DoUse uniqueID to deduplicate toasts that fire from repeated actions, like clicking a save button multiple times.
DoUse error type for failures that need attention but not immediate action — it persists until dismissed so the user won't miss it.
Don'tDon't use a toast for critical errors that block the user — use Banner for persistent, in-context messaging that requires acknowledgment.
Don'tDon't put long or multi-line content in a toast — it disappears after 5 seconds and the user may not finish reading.
Don'tDon't show form validation errors as toasts — use inline field validation so the user can see exactly which field needs fixing.

Anatomy

ElementDescription
BodyrequiredThe primary message text describing what happened or what the user should know.
End contentA trailing action like an Undo button or a link, placed after the body text.
Dismiss buttonrequiredA close button that lets the user manually dismiss the toast before auto-hide.

Import

ts
import {XDSToast} from '@xds/core/Toast'

Props

PropTypeDescription
bodyrequired
ReactNodePrimary message content.
type
'info' | 'error' (default: 'info')Toast type controlling background color. Error toasts persist until dismissed.
isAutoHide
booleanWhether the toast auto-dismisses. Defaults to true for info, false for error.
autoHideDuration
number (default: 5000)Duration in ms before auto-dismiss.
endContent
ReactNodeContent rendered at the trailing end (e.g. Undo button, link).
uniqueID
stringUnique identifier for deduplication.
collisionBehavior
'overwrite' | 'ignore' (default: 'overwrite')Behavior when a toast with matching uniqueID already exists.
onHide
(reason: "auto" | "manual") => voidCallback fired when the toast is removed.

Examples

Common configurations, variations, and states.
Toast — ActionPersistent toasts with a trailing button or link so the user can act on the notification, like undoing a delete or viewing a report.
tsx
// In production, use useXDSToast() hook for proper positioning, stacking, and lifecycle.
'use client';
import {XDSToast} from '@xds/core/Toast';
import {useXDSToast} from '@xds/core/Toast';
import {XDSButton} from '@xds/core/Button';
import {XDSLink} from '@xds/core/Link';
import {XDSVStack} from '@xds/core/Layout';
export default function ToastAction() {
const toast = useXDSToast();
return (
<XDSVStack gap={3}>
<XDSToast
type="info"
body="Item deleted"
endContent={
<XDSButton
label="Undo"
variant="secondary"
size="sm"
onClick={() => toast({body: 'Undo successful', type: 'info'})}
/>
}
isAutoHide={false}
autoHideDuration={5000}
isExiting={false}
onDismiss={() => {}}
/>
<XDSToast
type="info"
body="Your report is ready."
endContent={
<XDSLink href="#" label="View report" hasUnderline>
View report
</XDSLink>
}
isAutoHide={false}
autoHideDuration={5000}
isExiting={false}
onDismiss={() => {}}
/>
</XDSVStack>
);
}
Toast — DeduplicationPrevent duplicate toasts with uniqueID. Use ignore to keep the first toast, or overwrite to replace it with updated content like a progress percentage.
tsx
// In production, use useXDSToast() hook for proper positioning, stacking, and lifecycle.
'use client';
import {XDSToast} from '@xds/core/Toast';
import {useXDSToast} from '@xds/core/Toast';
import {XDSButton} from '@xds/core/Button';
import {XDSVStack, XDSHStack} from '@xds/core/Layout';
export default function ToastDeduplication() {
const toast = useXDSToast();
return (
<XDSVStack gap={3}>
<XDSToast
type="info"
body="You are offline"
isAutoHide={false}
autoHideDuration={5000}
isExiting={false}
onDismiss={() => {}}
/>
<XDSHStack gap={3} vAlign="center">
<XDSButton
label="Offline (ignore)"
variant="secondary"
size="sm"
onClick={() =>
toast({
body: 'You are offline',
uniqueID: 'offline',
collisionBehavior: 'ignore',
isAutoHide: false,
})
}
/>
<XDSButton
label="Progress (overwrite)"
variant="secondary"
size="sm"
onClick={() =>
toast({
body: `Uploading… ${Math.floor(Math.random() * 100)}%`,
uniqueID: 'upload-progress',
collisionBehavior: 'overwrite',
isAutoHide: false,
})
}
/>
</XDSHStack>
</XDSVStack>
);
}
Toast — DismissShow a persistent toast and dismiss it programmatically using the function returned by useXDSToast. Use for long-running operations that need manual cleanup.
tsx
// In production, use useXDSToast() hook for proper positioning, stacking, and lifecycle.
'use client';
import {useRef} from 'react';
import {XDSToast} from '@xds/core/Toast';
import {useXDSToast} from '@xds/core/Toast';
import {XDSButton} from '@xds/core/Button';
import {XDSVStack, XDSHStack} from '@xds/core/Layout';
export default function ToastDismiss() {
const toast = useXDSToast();
const dismissRef = useRef<(() => void) | null>(null);
return (
<XDSVStack gap={3}>
<XDSToast
type="info"
body="Uploading file…"
isAutoHide={false}
autoHideDuration={5000}
isExiting={false}
onDismiss={() => {}}
/>
<XDSHStack gap={3} vAlign="center">
<XDSButton
label="Show toast"
variant="secondary"
size="sm"
onClick={() => {
dismissRef.current = toast({
body: 'Uploading file…',
isAutoHide: false,
});
}}
/>
<XDSButton
label="Dismiss via code"
variant="ghost"
size="sm"
onClick={() => {
dismissRef.current?.();
dismissRef.current = null;
}}
/>
</XDSHStack>
</XDSVStack>
);
}
Toast — StackingMultiple toasts stacking vertically with smooth enter and exit animations. Click repeatedly to see how toasts queue and dismiss.
tsx
// In production, use useXDSToast() hook for proper positioning, stacking, and lifecycle.
'use client';
import {useRef} from 'react';
import {XDSToast} from '@xds/core/Toast';
import {useXDSToast} from '@xds/core/Toast';
import {XDSButton} from '@xds/core/Button';
import {XDSVStack} from '@xds/core/Layout';
const MESSAGES = [
{body: 'Changes saved.', type: 'info' as const},
{body: 'Failed to upload file.', type: 'error' as const},
{body: 'Message sent to Sarah Chen.', type: 'info' as const},
];
export default function ToastStacking() {
const toast = useXDSToast();
const countRef = useRef(0);
return (
<XDSVStack gap={3}>
{MESSAGES.map(msg => (
<XDSToast
key={msg.body}
type={msg.type}
body={msg.body}
isAutoHide={false}
autoHideDuration={5000}
isExiting={false}
onDismiss={() => {}}
/>
))}
<XDSButton
label="Show toast"
variant="secondary"
size="sm"
onClick={() => {
const msg = MESSAGES[countRef.current % MESSAGES.length];
countRef.current++;
toast(msg);
}}
/>
</XDSVStack>
);
}
Toast — TypesInfo and error toast variants side by side. Info toasts auto-dismiss after 5 seconds, error toasts persist until the user dismisses them.
tsx
// In production, use useXDSToast() hook for proper positioning, stacking, and lifecycle.
'use client';
import {XDSToast} from '@xds/core/Toast';
import {useXDSToast} from '@xds/core/Toast';
import {XDSButton} from '@xds/core/Button';
import {XDSVStack} from '@xds/core/Layout';
export default function ToastTypes() {
const toast = useXDSToast();
return (
<XDSVStack gap={3}>
<XDSToast
type="info"
body="Changes saved successfully."
endContent={
<XDSButton
label="Show toast"
variant="ghost"
size="sm"
onClick={() =>
toast({body: 'Changes saved successfully.', type: 'info'})
}
/>
}
isAutoHide={false}
autoHideDuration={5000}
isExiting={false}
onDismiss={() => {}}
/>
<XDSToast
type="error"
body="Failed to save changes."
endContent={
<XDSButton
label="Show toast"
variant="ghost"
size="sm"
onClick={() =>
toast({body: 'Failed to save changes.', type: 'error'})
}
/>
}
isAutoHide={false}
autoHideDuration={5000}
isExiting={false}
onDismiss={() => {}}
/>
</XDSVStack>
);
}

Showcase source

tsx
// In production, use useXDSToast() hook for proper positioning, stacking, and lifecycle.
'use client';
import {XDSToast} from '@xds/core/Toast';
import {useXDSToast} from '@xds/core/Toast';
import {XDSButton} from '@xds/core/Button';
export default function ToastShowcase() {
const toast = useXDSToast();
return (
<XDSToast
type="info"
body="Document saved successfully"
endContent={
<XDSButton
label="Show toast"
variant="ghost"
size="sm"
onClick={() => toast({body: 'Document saved successfully'})}
/>
}
isAutoHide={false}
autoHideDuration={5000}
isExiting={false}
onDismiss={() => {}}
/>
);
}