Toast
A transient notification used to provide feedback for actions, success states, warnings, or errors.
Use the toast helper anywhere in your app to trigger a notification — no setup needed beyond mounting FrappeUIProvider once at the root.
<script setup lang="ts">
import { Button, toast } from 'frappe-ui'
</script>
<template>
<Button label="Show toast" @click="toast.success('Workspace created')" />
</template>Examples
Toasts come in four visual types — message, info, success, warning, and error — and accept an optional description for secondary context.
<script setup lang="ts">
import { Button, toast } from 'frappe-ui'
</script>
<template>
<Button label="Workspace created" @click="toast.success('Workspace created')" />
<Button label="Link copied" @click="toast.info('Link copied to clipboard')" />
<Button
label="Comment posted"
@click="
toast.message('Comment posted', {
description: '“Looks good — shipping it!”',
})
"
/>
<Button
label="Profile updated"
@click="
toast.success('Profile updated', {
description: 'Your changes have been saved.',
})
"
/>
<Button
label="Payment failed"
@click="
toast.error('Payment failed', {
description: 'Your card was declined. Try a different one.',
})
"
/>
<Button
label="Storage almost full"
@click="
toast.warning('Storage almost full', {
description: 'You have used 9.2 GB of 10 GB. Upgrade to keep syncing.',
})
"
/>
</template>With action
Add an action to give the user a way to respond. Combine with duration: Infinity for messages that should wait for an explicit decision.
<script setup lang="ts">
import { Button, toast } from 'frappe-ui'
function postArchived() {
toast.success('Post archived', {
action: {
label: 'Undo',
onClick: () => toast.info('Archive undone'),
},
})
}
function newVersion() {
toast.info('A new version is available', {
description: 'Refresh to get the latest features.',
duration: Infinity,
action: {
label: 'Refresh',
onClick: () => toast.loading('Refreshing…'),
},
})
}
function backgroundSync() {
toast.info('Background sync in progress', {
duration: Infinity,
action: {
label: 'Cancel',
onClick: () => toast.dismiss(),
},
})
}
</script>
<template>
<Button label="Post archived" @click="postArchived" />
<Button label="New version" @click="newVersion" />
<Button label="Background sync" @click="backgroundSync" />
</template>Custom icon
Pass a render function to icon to replace the default type icon — handy for branding moments, custom imagery, or domain-specific glyphs. Use the lucide-* class form for any Lucide icon; size and color are controlled with regular utilities (size-4, text-ink-red-2, …).
<script setup lang="ts">
import { h } from 'vue'
import { Button, toast } from 'frappe-ui'
function celebrate() {
toast.success('You unlocked a new badge', {
icon: () => h('span', { class: 'lucide-sparkles size-4' }),
})
}
function favorited() {
toast('Added to favorites', {
description: 'Find it later in your saved items.',
icon: () => h('span', { class: 'lucide-heart size-4 text-ink-red-2' }),
})
}
function reminder() {
toast.message('Standup in 5 minutes', {
icon: () => h('span', { class: 'lucide-bell size-4' }),
})
}
</script>
<template>
<Button label="Celebrate" @click="celebrate" />
<Button label="Favorited" @click="favorited" />
<Button label="Reminder" @click="reminder" />
</template>Asynchronous
Use toast.promise to wire a single toast to a promise lifecycle, or pass an id to update an existing toast in place — useful for multi-step progress.
<script setup lang="ts">
import { Button, toast } from 'frappe-ui'
function sendInvite() {
toast.promise(new Promise<void>((resolve) => setTimeout(resolve, 1500)), {
loading: 'Sending invite to alex@example.com…',
success: 'Invite sent to alex@example.com',
error: 'Could not send invite',
})
}
function uploadFails() {
toast.promise(
new Promise<never>((_, reject) =>
setTimeout(() => reject(new Error('Network error')), 1500),
),
{
loading: 'Uploading report.pdf…',
success: 'Upload complete',
error: (err: Error) => `Upload failed: ${err.message}`,
},
)
}
function deployPipeline() {
const steps = [
{ label: 'Linting…', delay: 0 },
{ label: 'Type-checking…', delay: 600 },
{ label: 'Running tests…', delay: 1200 },
{ label: 'Building…', delay: 1900 },
{ label: 'Deploying to production…', delay: 2700 },
]
const id = toast.loading(steps[0].label)
steps.slice(1).forEach((step) => {
setTimeout(() => toast.loading(step.label, { id }), step.delay)
})
setTimeout(
() =>
toast.success('Deployed to production', {
id,
description: 'v2.4.1 is live • took 3.6s',
}),
3500,
)
}
</script>
<template>
<Button label="Send invite" @click="sendInvite" />
<Button label="Upload fails" @click="uploadFails" />
<Button label="Deploy pipeline" @click="deployPipeline" />
</template>