Справочник
Архитектура
useToast() / toast (singleton)
│
├── buildToastApi(context)
│ toast(), toast.success/error/warning/info/loading/custom()
│ toast.promise() — updates type + restarts timer
│ toast.undo() — wraps options.undo
│ toast.dismiss() — proxies to queue.dismiss()
│
▼
ToastContext
│ addToast() → isServer ? ToastBuffer : ToastQueue.add()
│ dismiss() → ToastQueue.dismiss()
│ update() → ToastQueue.update()
│
▼
ToastQueue GroupManager
active: ToastItem[] ◄───────────────────┐
pending: ToastItem[] add(id, key) │
timers: Map<id, UndoTimer> remove(id, key)│
toggleExpand() │
add() — dedup / preempt / sort pending │
remove() — free slot, promote from pending│
update() — merge + restart timer on duration│
dismiss() — calls onClose, remove │
│
UndoTimer │
setTimeout/setInterval, pause/resume │
remaining: number (0–1) ────────────────►│ ToastItem.remaining.value
onExpire: () => queue.remove(id) │
│
ToastBuffer (SSR) │
push() — store before window exists │
flush() — replay into queue at mount │
onFlush() — called by ToastContainer │
│
ToastContainer.vue │
Teleport → body │
TransitionGroup (slide + fade per position)│
hover → queue.pauseAll() / resumeAll() │
visibilitychange → pause/resume │
position/theme/maxVisible default to │
inject(GLOBAL_OPTIONS_KEY) when the │
matching prop isn't passed explicitly │
slot: #toast / #toast-icon / … │
│ │
└── Toast.vue │
swipe (touch) │
aria role + aria-live │
ToastIcon.vue (SVG + spinner) │
ToastProgressBar.vue (scaleX) │
action / undo buttons │
group counter (click → toggleExpand)│
Plugin (VueToastPlugin) Nuxt Module
app.use() → installContext() defineNuxtModule()
provide(TOAST_CONTEXT_KEY, ctx) addPlugin(resolver.resolve('./plugin'))
provide(GLOBAL_OPTIONS_KEY, opts) → own dist/nuxt/plugin.{js,cjs} entry
app.component('ToastContainer', …) addImports()/addComponent() source from
the package's main entry (already built)
css injectПоддержка SSR
| Сценарий | Поведение |
|---|---|
typeof window === 'undefined' | Вызовы toast() буферизуются в ToastBuffer; browser API не затрагивается |
<ToastContainer> монтируется на клиенте | Буфер сбрасывается через 100 мс со всеми ожидающими тостами |
ignoreSSR: true | Буфер отключён; тосты, вызванные на SSR, тихо отбрасываются |
| Гидратация Nuxt | Плагин работает и на SSR тоже (это универсальный плагин Nuxt, не только клиентский) — отсутствие HTML тостов на сервере связано с рендером ToastContainer, а не с плагином |
ts
// nuxt.config.ts — отключить SSR-буфер, если тосты никогда не вызываются на сервере
vueToastKit: {
ignoreSSR: true
}Доступность
| Возможность | Реализация |
|---|---|
role="alert" / role="status" | alert для типа error/warning или приоритета critical; status в остальных случаях |
aria-live | "assertive" для приоритета critical (либо переопределение options.ariaLive); "polite" в остальных случаях |
aria-atomic="true" | Всегда установлен на элементе тоста |
tabindex="0" | Только когда тост закрываемый, имеет действие или кнопку отмены |
Клавиша Escape | Закрывает тост в фокусе (только если закрываемый); фокус возвращается на элемент, активный до появления тоста |
| Кнопка закрытия | aria-label="Close" |
| Счётчик группы | role="button" + aria-label="Show all (N)" |
ToastIcon / ToastProgressBar | aria-hidden="true" (декоративные) |
Обёртка позиции <ToastContainer> | role="region" + aria-label="Notifications", только пока в этой позиции есть активные тосты |
| Клавиатура | Escape закрывает тост в фокусе; другого встроенного клавиатурного взаимодействия нет (кнопки закрытия/действия/отмены — обычные фокусируемые кнопки) |
Размер бандла и peer-зависимости
| Точка входа | Размер (gzip) | Peer-зависимости |
|---|---|---|
vue-toast-kit (JS) | ~9.2 KB | vue ^3.3 |
vue-toast-kit/style (CSS) | ~2.4 KB | — |
vue-toast-kit/nuxt | ~0.6 KB | vue ^3.3, @nuxt/kit |
Поставляется как tree-shakeable ESM (vue-toast-kit.js) и CommonJS (vue-toast-kit.cjs).
Сравнение
| vue-toastification | vue-sonner | vue-toast-kit |
|---|---|---|
useToast() | — | useToast() |
toast(msg, { type: TYPE.SUCCESS }) | toast.success(msg) | toast.success(msg) |
toast(msg, { type: TYPE.ERROR }) | toast.error(msg) | toast.error(msg) |
toast(msg, { type: TYPE.WARNING }) | — | toast.warning(msg) |
toast(msg, { type: TYPE.INFO }) | toast(msg) | toast.info(msg) |
toast.loading(msg) | toast.loading(msg) | toast.loading(msg) |
POSITION.BOTTOM_RIGHT | — | 'bottom-right' |
POSITION.TOP_CENTER | — | 'top-center' |
toast.dismiss(id) | toast.dismiss(id) | toast.dismiss(id) |
toast.update(id, opts) | — | toast.update(id, opts) |
| — | toast.promise() | toast.promise() |
| — | — | toast.undo() |
| — | — | Очередь приоритетов |
| — | — | Группировка |
| — | — | useToastState() headless |
| — | — | createToastContext() |
Миграция
Миграция с vue-toastification
ts
// До
import { useToast, TYPE, POSITION } from 'vue-toastification'
const toast = useToast()
toast('Hello', { type: TYPE.SUCCESS, position: POSITION.BOTTOM_RIGHT })
// После
import { useToast } from 'vue-toast-kit'
const toast = useToast()
toast.success('Hello') // позиция задаётся глобально в плагинеМиграция с vue-sonner
toast.success(), toast.error(), toast.promise() и toast.dismiss() идентичны. Единственное отличие — <ToastContainer /> заменяет <Toaster />:
vue
<!-- До (vue-sonner) -->
<Toaster position="bottom-right" />
<!-- После (vue-toast-kit) -->
<ToastContainer position="bottom-right" />Разработка
bash
git clone https://github.com/macrulezru/vue-toast-kit.git
cd vue-toast-kit
npm install
npm run build # vite build + tsc --emitDeclarationOnly
npm run typecheck # tsc --noEmit
npm run lint # eslint --fix
npm test # vitest runЗапуск интерактивного демо — см. Демо.
Лицензия
MIT