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.

vue
<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.

vue
<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.

vue
<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, …).

vue
<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.

vue
<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>