Toast
Transient notification queue with swipe to dismiss.
A transient notification, with a queue and swipe to dismiss.
The queue lives outside React, so toast.show() works from anywhere — API clients, event handlers, code with no component around it. PanelUIProvider mounts the viewport for you.
Use it for something that happened and needs no response. For a condition that persists on the screen, use Alert.
Installation
Toast ships with the library — no separate install.
import { Toast, Button, useToast } from 'panelui-native';Or copy the source into your project, to own and edit it:
npx panelui-cli@latest add toastUsage
const { toast } = useToast();
// A bare string
toast.show('Link copied');
// A config object
toast.show({
variant: 'success',
label: 'Deployment complete',
description: 'panelui.dev is live on production.',
actionLabel: 'View',
onActionPress: ({ hide }) => hide(),
});
// A custom component
toast.show({
component: ({ hide }) => (
<Toast variant="info" onHide={hide}>
<Toast.Indicator />
<Toast.Content>
<Toast.Title>Custom</Toast.Title>
</Toast.Content>
<Toast.Close />
</Toast>
),
});Composition
<Toast>
<Toast.Indicator />
<Toast.Content>
<Toast.Title>…</Toast.Title>
<Toast.Description>…</Toast.Description>
</Toast.Content>
<Toast.Action>…</Toast.Action>
<Toast.Close />
</Toast>Toast.Indicator— Status icon, picked from the variant.Toast.Content— Flex-1 wrapper for title and description.Toast.Title— Heading, coloured by the variant.Toast.Description— Body text.Toast.Action— Trailing action button. Dismisses the toast after its ownonPress.Toast.Close— Icon-only dismiss button.
Examples
Firing one
Toasts are queued through useToast, so any component can raise one without rendering it.
const { toast } = useToast();
<Button
onPress={() =>
toast({
variant: 'success',
title: 'Saved',
description: 'Your changes are live.',
})
}
>
Save
</Button>With an action
toast({
variant: 'default',
title: 'Message archived',
action: { label: 'Undo', onPress: restore },
});An error you have to dismiss
toast({
variant: 'destructive',
title: 'Upload failed',
description: 'The file is larger than 25 MB.',
duration: 0, // stays until dismissed
});Versions
Simple string
A string on its own. No title, no description, no action — the whole toast is the sentence, which is what a copy-to-clipboard or a saved-draft actually has to say.
toast.show('Link copied to clipboard');With action
A title, a description and one thing to do about the result. actionLabel draws the control; the toast stays up long enough to reach it.
toast.show({
variant: 'success',
label: 'Deployment complete',
description: 'panelui.dev is live on production.',
actionLabel: 'View',
});Destructive, top
A failure raised at the top edge. placement is per-toast rather than per-app, because the edge a message belongs at follows from the message: a result of something you just did belongs near your thumb, and a failure you did not ask for does not.
toast.show({
variant: 'destructive',
label: 'Upload failed',
description: 'The file exceeds the 25 MB limit.',
placement: 'top',
});Stack four
Four arriving in turn. Three are visible at once — the newest in front, the rest peeking out behind it — and the deck collapses as each is dismissed.
They are fired a fifth of a second apart rather than together, because the deck is built by things arriving: four on one frame is a stack that was already there.
(['default', 'info', 'success', 'warning'] as const).forEach((variant, index) =>
setTimeout(
() =>
toast.show({
variant,
label: `Notification ${index + 1}`,
description: 'Swipe down to dismiss the front one.',
duration: 8000,
}),
index * 220
)
);Hide all
Clearing the whole queue at once, whatever is in it. Use it when the thing the toasts were about has gone — a screen the user has left, a job they cancelled.
toast.hideAll();Custom component
The toast drawn entirely by the caller. The deck still owns its timing, its position and its swipe; component only replaces what is inside. hide is handed in so a control of your own can dismiss it.
toast.show({
duration: 6000,
component: ({ hide }) => (
<Toast variant="info" onHide={hide}>
<Toast.Indicator />
<Toast.Content>
<Toast.Title>Custom component</Toast.Title>
<Toast.Description>Rendered entirely by the caller.</Toast.Description>
</Toast.Content>
<Toast.Close />
</Toast>
),
});Lifecycle contract
| Case | Contract |
|---|---|
| default initialization | A toast begins with its complete visible-time duration. |
| controlled acceptance | Not applicable: the toast store owns entries rather than accepting a value prop. |
| controlled rejection | Not applicable: dismiss requests mutate the owning store directly. |
| external reset | Clearing or replacing the viewport does not spend background time. |
| disabled path | Inactive AppState and an unmounted viewport pause every countdown. |
| prop replacement | Duration is captured per toast; viewport lifecycle changes preserve remaining time. |
| unmount cleanup | Viewport release pauses timers and removes AppState ownership. |
| reduced motion | Not applicable to countdown ownership; visual transitions own motion separately. |
| callback counts | Each timer fires dismissal once after its complete foreground-visible duration. |
Executable evidence: packages/panelui/test/toast-timer-lifecycle.test.mjs (3 tests).
Variants
variant
default(default)infosuccesswarningdestructive
toast({ variant: 'default', title: 'Saved' });
toast({ variant: 'info', title: 'Syncing' });
toast({ variant: 'success', title: 'Deployed' });
toast({ variant: 'warning', title: 'Almost out of space' });
toast({ variant: 'destructive', title: 'Upload failed' });API Reference
Toast
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | |
onHide | () => void | — | Called when the close button is pressed or the toast is swiped away. |
Toast.Indicator
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | |
iconProps | { size?: number; color?: string } | — |
Toast.Close
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — |
Every part also accepts the underlying React Native props (ViewProps or TextProps) and a className for Tailwind utilities.
Notes
Toasts stack as an overlapping deck: the newest is fully visible and the ones behind peek out, with anything past the third fading rather than accumulating. Swiping toward the edge the toast entered from dismisses it; dragging the other way rubber-bands.
Auto-dismiss durations count visible foreground time: countdowns pause while the app is inactive or in the background, then resume where they left off. toast.hide(id) dismisses one, toast.hideAll() clears the queue. A duration of 0 keeps a toast up until it is dismissed.
Public exports
Values: Toast, ToastViewport, toast, useToast
Types: ToastProps, ToastOptions, ToastItem, ToastVariant, ToastPlacement, ToastHandle, ToastIndicatorProps, ToastCloseProps