Toasts
Short confirmations and failures, raised from anywhere with the toast function.
<script setup lang="ts">
import { Button } from '@shared/components/ui/button'
import { toast } from 'vue-sonner'
</script>
<template>
<div class="flex flex-wrap gap-2">
<Button variant="outline" size="sm" @click="toast('Draft saved')">
Message
</Button>
<Button variant="outline" size="sm" @click="toast.success('Changes saved')">
Success
</Button>
<Button variant="outline" size="sm" @click="toast.error('That email is already in use')">
Error
</Button>
</div>
</template>Usage
Toasts come from vue-sonner. Import toast and call it. There is nothing to add to the page: the template mounts one <Toaster> in App.vue, and every toast in the app goes through it.
<script setup lang="ts">
import { toast } from 'vue-sonner'
</script>
<template>
<button @click="toast.success('Changes saved')">
Save
</button>
</template>The template's <Toaster> is set to the top right, three toasts at a time, four seconds each, with rich colors and a close button.
Examples
With a description and an action
An action turns a toast into an undo, which is the honest alternative to a confirm dialog for something reversible.
<script setup lang="ts">
import { Button } from '@shared/components/ui/button'
import { toast } from 'vue-sonner'
function remove(): void {
toast.success('Invoice deleted', {
description: 'INV-2043 was moved to the bin.',
action: {
label: 'Undo',
onClick: () => toast.success('Invoice restored'),
},
})
}
</script>
<template>
<Button variant="outline" size="sm" @click="remove">
Delete invoice
</Button>
</template>Tracking a request
toast.promise shows a loading toast and replaces it with the success or error message when the promise settles.
<script setup lang="ts">
import { Button } from '@shared/components/ui/button'
import { toast } from 'vue-sonner'
function sync(): void {
const request = new Promise<string>((resolve) => {
setTimeout(() => resolve('4 records'), 1500)
})
toast.promise(request, {
loading: 'Syncing changes…',
success: (result: string) => `Synced ${result}`,
error: 'Sync failed',
})
}
</script>
<template>
<Button variant="outline" size="sm" @click="sync">
Sync
</Button>
</template>API
The template calls toast from vue-sonner directly. The forms it uses:
| Call | Description |
|---|---|
toast(message, options?) | A plain message. |
toast.success(message, options?) | Success styling. |
toast.error(message, options?) | Error styling. |
toast.info(message, options?) | Informational styling. |
toast.warning(message, options?) | Warning styling. |
toast.loading(message, options?) | A toast that stays until it is replaced or dismissed. Returns its id. |
toast.promise(promise, handlers) | Loading, then success or error from { loading, success, error }. |
toast.dismiss(id?) | Closes one toast, or all of them. |
Options used in the template: description, action: { label, onClick }, duration, and id to replace an existing toast.
Some of the template raises toasts for you. useApiError turns a failed request into an error toast, useCrud confirms a create, update or delete, the v-copy directive confirms a copy, and the export button reports what it wrote.
Accessibility
- The toaster is a polite live region, so a new toast is announced without moving focus.
Alt+Tmoves focus to the toasts, andEscapereturns focus to where it was.- Each toast has a close button, and hovering pauses the timer.
- A toast that carries information the reader must act on belongs on the page as well; four seconds is not long enough to read anything complex.