useNotifications
Notification lifecycle management with severity levels, state mutations, toast queuing, and auto-dismiss.
Installation
Install the Notifications plugin in your app’s entry point:
import { createApp } from 'vue'
import { createNotificationsPlugin } from '@vuetify/v0'
import App from './App.vue'
const app = createApp(App)
app.use(createNotificationsPlugin())
app.mount('#app')Usage
Once the plugin is installed, use the useNotifications composable in any component:
<script setup lang="ts">
import { useNotifications } from '@vuetify/v0'
const notifications = useNotifications()
function onSave () {
notifications.send({
subject: 'Changes saved',
severity: 'success',
timeout: 3000,
})
}
function onError () {
notifications.send({
subject: 'Build failed',
severity: 'error',
timeout: -1,
})
}
</script>
<template>
<button @click="onSave">
Save
</button>
</template>Adapters
Adapters let you swap the underlying notification service without changing your application code.
| Adapter | Import | Description |
|---|---|---|
KnockNotificationsAdapter | @vuetify/v0/notifications | Knock↗︎ integration |
NovuNotificationsAdapter | @vuetify/v0/notifications | Novu↗︎ integration |
Knock
Knock↗︎ is a notification infrastructure platform with feeds, preferences, and multi-channel delivery. Install their JavaScript SDK↗︎ to get started. Supports both inbound (feed → notifications) and outbound (read/archive → Knock API).
pnpm add @knocklabs/clientnpm install @knocklabs/clientyarn add @knocklabs/clientbun add @knocklabs/clientimport { createApp } from 'vue'
import { createNotificationsPlugin } from '@vuetify/v0'
import { KnockNotificationsAdapter } from '@vuetify/v0/notifications'
import { feed } from './plugins/knock'
import App from './App.vue'
const app = createApp(App)
app.use(
createNotificationsPlugin({
adapter: new KnockNotificationsAdapter(feed),
})
)
app.mount('#app')import Knock from '@knocklabs/client'
export const knock = new Knock(import.meta.env.VITE_KNOCK_PUBLIC_KEY)
knock.authenticate(import.meta.env.VITE_KNOCK_USER_ID)
export const feed = knock.feeds.initialize(
import.meta.env.VITE_KNOCK_FEED_CHANNEL_ID
)Novu
Novu↗︎ is an open-source notification infrastructure with in-app feeds, digests, and multi-channel delivery. Install their JavaScript SDK↗︎ to get started. Supports both inbound (feed → notifications) and outbound (read/unread/seen/archive/unarchive → Novu API).
The adapter maps Novu severity strings to NotificationSeverity by default: critical/high → error, medium → warning, low → info. Pass a custom severity function to override.
pnpm add @novu/jsnpm install @novu/jsyarn add @novu/jsbun add @novu/jsimport { createApp } from 'vue'
import { createNotificationsPlugin } from '@vuetify/v0'
import { NovuNotificationsAdapter } from '@vuetify/v0/notifications'
import { novu } from './plugins/novu'
import App from './App.vue'
const app = createApp(App)
app.use(
createNotificationsPlugin({
adapter: new NovuNotificationsAdapter(novu),
})
)
app.mount('#app')import { Novu } from '@novu/js'
export const novu = new Novu({
subscriberId: import.meta.env.VITE_NOVU_SUBSCRIBER_ID,
applicationIdentifier: import.meta.env.VITE_NOVU_APP_ID,
})Custom Adapters
Extend NotificationsAdapter to connect any backend:
import { NotificationsAdapter } from '@vuetify/v0/notifications'
import type { NotificationsAdapterContext } from '@vuetify/v0'
class MyBackendAdapter extends NotificationsAdapter {
setup (context: NotificationsAdapterContext) {
// Wire inbound: push notifications into the registry
myBackend.onMessage(msg => {
context.send({ id: msg.id, title: msg.title, body: msg.body })
})
// Wire outbound: sync read/archive actions back to the backend
context.on('notification:read', (data: any) => {
myBackend.markRead(data.id)
})
}
dispose () {
myBackend.disconnect()
}
}
app.use(createNotificationsPlugin({ adapter: new MyBackendAdapter() }))Adapter context methods:
| Method | Purpose |
|---|---|
send(input) | Register and enqueue for toast display (real-time inbound) |
register(input) | Register in history only — no toast (initial/historical load) |
on(event, handler) | Subscribe to outbound lifecycle events |
off(event, handler) | Unsubscribe from a lifecycle event |
Custom Ticket Fields
Extend NotificationTicketInput to add domain-specific fields. Pass the type parameter through the adapter and plugin:
import { NotificationsAdapter } from '@vuetify/v0/notifications'
import type { NotificationTicketInput, NotificationsAdapterContext } from '@vuetify/v0'
interface AppNotification extends NotificationTicketInput {
priority: 'low' | 'medium' | 'high'
imageUrl?: string
}
class MyBackendAdapter extends NotificationsAdapter<AppNotification> {
setup (context: NotificationsAdapterContext<AppNotification>) {
myBackend.onMessage(msg => {
context.send({
id: msg.id,
subject: msg.title,
priority: msg.priority, // custom field
imageUrl: msg.imageUrl, // custom field
})
})
}
}
app.use(createNotificationsPlugin<AppNotification>({ adapter: new MyBackendAdapter() }))Custom fields are preserved on the ticket and accessible anywhere you inject the notifications context.
Architecture
createNotifications layers notification semantics on top of the registry and queue primitives, with plugin installation via createPluginContext:
Reactivity
API
| Method | Description |
|---|---|
send(input) | Create notification + enqueue for toast display |
register(input) | Create notification in registry only (no toast). Use for historical items |
queue | Queue context — queue.values(), queue.pause(), queue.resume() |
read(id) / unread(id) | Toggle read state |
seen(id) | Mark as seen |
archive(id) / unarchive(id) | Toggle archive state |
snooze(id, until) / wake(id) | Snooze with expiry |
readAll() / archiveAll() | Bulk operations |
onboard(items) | Bulk-register enriched notifications into registry (no toast) |
clear() | Remove all notifications from the registry |
dispose() | Tear down event listeners and clear the registry |
Examples
Click Simulate Event to push notifications
Recipes
Severity Levels
The severity field categorizes notifications by urgency. It maps to ARIA live region roles automatically:
| Value | ARIA role | Use for |
|---|---|---|
'error' | role="alert" | Failures, errors, destructive outcomes |
'warning' | role="alert" | Degraded state, approaching limits |
'info' | role="status" | Neutral updates, background activity |
'success' | role="status" | Completed actions, positive outcomes |
NotificationSeverity is extensible — custom values like 'critical' are accepted with autocomplete for the four defaults.
FAQ
send() registers a notification and enqueues it for toast display — use it for real-time, in-the-moment events. register() adds it to the registry only, with no toast, which is what you want when loading historical or initial notifications.
Pass timeout: -1 on send(). A positive timeout (e.g. 3000) auto-dismisses after that many milliseconds; -1 makes it persist until dismissed explicitly.
They’re independent. seen drives the unseen badge count (cleared when the inbox is opened); read drives visual weight (cleared when the user actually reads it) — mirroring how GitHub and Slack distinguish the two.
Pass the matching adapter to createNotificationsPlugin — KnockNotificationsAdapter or NovuNotificationsAdapter from @vuetify/v0/notifications. Both handle inbound (feed → registry) and outbound (read/archive → service) sync. For any other backend, extend NotificationsAdapter and wire its setup(context).
Yes. Extend NotificationTicketInput with your own fields (e.g. priority, imageUrl) and pass the type through the adapter and createNotificationsPlugin<T>. Custom fields are preserved on the ticket and readable anywhere you inject the context.
It maps to an ARIA live-region role automatically: error and warning become role="alert", while info and success become role="status". NotificationSeverity is extensible, so custom values are accepted alongside the four defaults.