Toast
Queue concise feedback and announce it without interrupting the current task.
Usage
Auto dismiss
Dismiss transient feedback automatically after a short delay while keeping a visible close action.
Dismiss transient feedback automatically after a short delay while keeping a visible close action.
<!-- Toast / Automatic -->
<script setup lang="ts">
import { ToastClose, ToastProvider, ToastRoot, ToastTitle, ToastViewport } from '@sectile/vue/toast'
</script>
<template>
<ToastProvider :default-duration-ms="5000" :max-visible="3" v-slot="{ toasts, toast }">
<button @click="toast({ id: crypto.randomUUID(), title: 'Release saved', kind: 'success' })">Notify</button>
<ToastViewport>
<ToastRoot v-for="item in toasts" :key="item.id" :value="item.id">
<ToastTitle /><ToastClose>Dismiss</ToastClose>
</ToastRoot>
</ToastViewport>
</ToastProvider>
</template>Persistent
Keep feedback visible until the user explicitly dismisses it.
Keep feedback visible until the user explicitly dismisses it.
<!-- Toast / Persistent -->
<script setup lang="ts">
import { ToastClose, ToastProvider, ToastRoot, ToastTitle, ToastViewport } from '@sectile/vue/toast'
</script>
<template>
<ToastProvider :default-duration-ms="null" :max-visible="3" v-slot="{ toasts, toast }">
<button @click="toast({ id: crypto.randomUUID(), title: 'Release saved', kind: 'success' })">Notify</button>
<ToastViewport>
<ToastRoot v-for="item in toasts" :key="item.id" :value="item.id">
<ToastTitle /><ToastClose>Dismiss</ToastClose>
</ToastRoot>
</ToastViewport>
</ToastProvider>
</template>Limited
Enforce the configured item or visible-notification limit without losing existing values.
Enforce the configured item or visible-notification limit without losing existing values.
<!-- Toast / Limited -->
<script setup lang="ts">
import { ToastClose, ToastProvider, ToastRoot, ToastTitle, ToastViewport } from '@sectile/vue/toast'
</script>
<template>
<ToastProvider :default-duration-ms="5000" :max-visible="2" v-slot="{ toasts, toast }">
<button @click="toast({ id: crypto.randomUUID(), title: 'Release saved', kind: 'success' })">Notify</button>
<ToastViewport>
<ToastRoot v-for="item in toasts" :key="item.id" :value="item.id">
<ToastTitle /><ToastClose>Dismiss</ToastClose>
</ToastRoot>
</ToastViewport>
</ToastProvider>
</template>Calling from setup
Call useToast() in the setup of a component below ToastProvider. Its returned state and functions can be used from templates, event handlers, or asynchronous functions. The component that declares the provider is above that provider and cannot read its context from the same setup. Place callers inside the provider slot.
<!-- AppShell.vue -->
<ToastProvider v-slot="{ toasts }">
<RequestButton />
<ToastViewport class="toast-viewport">
<ToastRoot v-for="item in toasts" :key="item.id" :value="item.id" class="toast-item">
<ToastTitle />
<ToastDescription />
<ToastClose>Dismiss</ToastClose>
</ToastRoot>
</ToastViewport>
</ToastProvider>// RequestButton.vue <script setup>
const { toast, update } = useToast()
async function save() {
const id = crypto.randomUUID()
toast({ id, title: 'Saving', kind: 'deployment-pending', durationMs: null })
try {
const result = await saveRelease()
update(id, { title: 'Saved', kind: 'deployment-complete', durationMs: 3_000 })
return result
} catch (error) {
update(id, { title: 'Save failed', description: 'Try again.', kind: 'error', durationMs: 5_000 })
throw error
}
}Sectile does not execute request functions or consume their errors. The application chooses pending, success, and failure copy, timing, and error disclosure. The application that composes the provider's compound parts also owns markup, icons, classes, placement, and motion.
kind is a user-defined string, not a predefined enum. An omitted or blank value defaults to info; every other value is preserved through data-kind. For backward-compatible accessibility semantics, exactly error uses role="alert" and every other kind uses role="status".
Styling directly with CSS
When no icon or extra configuration is needed, use data-kind selectors without a registry.
.toast-item[data-kind='deployment-pending'] {
background: var(--toast-pending-background);
}
.toast-item[data-kind='deployment-complete'] {
background: var(--toast-complete-background);
}Registering classes and icons
Register kind presentation in a normal application object rather than a Sectile global registry. Handle unregistered values with an explicit fallback.
// toast-kinds.ts
import type { Component } from 'vue'
import InfoIcon from './InfoIcon.vue'
import SpinnerIcon from './SpinnerIcon.vue'
import SuccessIcon from './SuccessIcon.vue'
import ErrorIcon from './ErrorIcon.vue'
interface ToastKindPresentation {
readonly class: string
readonly icon: Component
}
export const toastKinds = {
info: { class: 'toast--info', icon: InfoIcon },
'deployment-pending': { class: 'toast--pending', icon: SpinnerIcon },
'deployment-complete': { class: 'toast--complete', icon: SuccessIcon },
error: { class: 'toast--error', icon: ErrorIcon },
} as const satisfies Record<string, ToastKindPresentation>
export type AppToastKind = keyof typeof toastKinds
const fallbackKind: ToastKindPresentation = {
class: 'toast--unknown',
icon: InfoIcon,
}
export function resolveToastKind(kind: string): ToastKindPresentation {
return kind in toastKinds
? toastKinds[kind as AppToastKind]
: fallbackKind
}<ToastRoot
v-for="item in toasts"
:key="item.id"
:value="item.id"
:class="resolveToastKind(item.kind).class"
>
<component :is="resolveToastKind(item.kind).icon" />
<ToastTitle />
<ToastDescription />
</ToastRoot>Restricting kinds inside an application
Sectile accepts every string, while an application wrapper can narrow calls to registered kinds.
// use-app-toast.ts
import type { ToastInput } from '@sectile/vue/toast'
import { useToast } from '@sectile/vue/toast'
import type { AppToastKind } from './toast-kinds'
type AppToastInput = Omit<ToastInput<string>, 'kind'> & {
readonly kind?: AppToastKind
}
export function useAppToast() {
const api = useToast()
return {
...api,
toast(input: AppToastInput) {
api.toast(input)
},
}
}API
Vue package: @sectile/vue/toast
ToastProviderToastPortalToastViewportToastRootToastTitleToastDescriptionToastClose
Functions
useToast
function useToast(): UseToastReturnProps
ToastProviderProps
closeLabelAccessible label announced for each notification close action.
defaultDurationMsInitial timer duration in milliseconds.
dismissOnEscapeWhether Escape dismisses the focused notification.
hotkeyDocument hotkey that moves focus to the notification viewport, or false to disable it.
initialToastsNotifications present when the provider first mounts.
maxVisibleMaximum number of notifications shown at once.
pauseOnWindowBlurWhether automatic dismissal pauses while the browser window is inactive.
swipeDirectionDirection in which a pointer swipe dismisses a notification.
swipeThresholdPointer travel in pixels required to dismiss by swiping.
toastsCurrent notifications when the provider is controlled by the parent.
ToastPartProps
asElement or component rendered for this part.
asChildWhether to merge this part into its single child instead of rendering a wrapper.
ToastPortalProps
deferWhether Teleport target resolution waits until the end of the current mount or update tick.
disabledWhether interaction is unavailable.
toTeleport target for portalled content.
ToastRootProps
asElement or component rendered for this part.
asChildWhether to merge this part into its single child instead of rendering a wrapper.
valueCurrent value exposed by this contract.
Slots
ToastProviderSlotProps
dismissDismisses one notification.
dismissAllDismisses every notification.
pausedWhether automatic updates are paused.
toastNotification represented by this item.
toastsCurrent notification collection.
updateUpdates one notification without replacing its identifier.
ToastRootSlotProps
openWhether the associated popup or disclosure is open.
toastNotification represented by this item.
Events
ToastProvider
update:toastsEmitted when the provider requests a new controlled notification collection.
Other types
UseToastReturn
| Name | Type | Required |
|---|---|---|
toasts | ComputedRef<readonly ToastItem<string>[]> | Yes |
paused | ComputedRef<boolean> | Yes |
toast | void | Yes |
update | void | Yes |
dismiss | void | Yes |
dismissAll | void | Yes |
Parts
Shared scope: [data-scope="toast"]. Combine it with a part selector to keep styles local to this component.
| Part | Selector | Role | Extra attributes |
|---|---|---|---|
viewport | [data-part="viewport"] | Clips and positions the currently visible content. | — |
root | [data-part="root"] | Defines the component boundary and owns its composed parts. | — |
title | [data-part="title"] | Labels the associated content. | — |
description | [data-part="description"] | Describes the associated content or decision. | — |
close | [data-part="close"] | Closes or dismisses the current surface. | — |
Keyboard interaction
| Key | Behavior |
|---|---|
| F8 | Move focus to the notification viewport. |
| Tab / Shift+Tab | Move between notification action controls. |
| Escape | Dismiss the focused notification. |
| Pointer swipe | Dismiss a notification after moving it past the configured threshold. |
Accessibility
The viewport preserves announcement order and keyboard access; each visible toast has a localized dismiss action and pauses while interaction or window state requires it.
