Get Started
Introduction
Components
Accordion
Badge
Button
Card
Checkbox
Command
Dialog
Dropdown Menu
Input
Select
Switch
Table
Tabs
Toast
Tooltip
Forms
Introduction
Validation
Field Arrays

Toast Queue

Signal-backed notification queue composed with the existing ToastProvider, Toast, ToastTitle, ToastDescription, and ToastClose components.

#Preview

Notification Queue

Notifications are rendered through the shared ToastProvider portal.

Active toasts
0
Exiting
0
Top variant
none

Source queue

0 tracked
No notifications in the queue

Event log

Queue ready
1"use client"23import { createSignal, createMemo, createEffect, onCleanup } from '@barefootjs/client'4import {5  ToastProvider,6  Toast,7  ToastTitle,8  ToastDescription,9  ToastClose,10} from '@ui/components/ui/toast'1112type QueueToast = {13  id: number14  variant: 'success' | 'error' | 'warning' | 'info'15  title: string16  description: string17  duration: number18  status: 'visible' | 'exiting'19}2021const removeTimers = new Map<number, ReturnType<typeof setTimeout>>()2223export function ToastQueueDemo() {24  const [toasts, setToasts] = createSignal<QueueToast[]>([])25  const activeCount = createMemo(() => toasts().filter(t => t.status !== 'exiting').length)2627  const dismissToast = (id: number) => {28    setToasts(prev => prev.map(t => t.id === id ? { ...t, status: 'exiting' } : t))29  }3031  createEffect(() => {32    const current = toasts()33    current.forEach(toast => {34      if (toast.status !== 'exiting' || removeTimers.has(toast.id)) return35      removeTimers.set(toast.id, setTimeout(() => {36        removeTimers.delete(toast.id)37        setToasts(prev => prev.filter(t => t.id !== toast.id))38      }, 340))39    })40  })4142  createEffect(() => {43    onCleanup(() => removeTimers.forEach(timer => clearTimeout(timer)))44  })4546  return (47    <div>48      <button onClick={() => setToasts(prev => [makeToast(), ...prev])}>49        Add batch50      </button>51      <span>{activeCount()} active toasts</span>5253      <ToastProvider position="bottom-right">54        {toasts().map(toast => (55          <Toast56            key={toast.id}57            variant={toast.variant}58            open={toast.status !== 'exiting'}59            duration={toast.duration}60            onOpenChange={open => {61              if (!open) dismissToast(toast.id)62            }}63          >64            <div className="flex-1">65              <ToastTitle>{toast.title}</ToastTitle>66              <ToastDescription>{toast.description}</ToastDescription>67            </div>68            <ToastClose />69          </Toast>70        ))}71      </ToastProvider>72    </div>73  )74}

#Features

Toast Component Composition

The queue renders each notification with the existing Toast subcomponents instead of hand-written toast markup, so variants, roles, close behavior, and animation classes stay aligned with the UI registry.

Owner-Scope Tracking

ToastProvider owns the portal into document.body, preserving the signal ownership chain after the provider node is moved outside the component tree.

Per-Toast Cleanup

Toast handles auto-dismiss through its duration prop, while the queue tracks exit-removal timers and clears them through onCleanup.

Stack Ordering + Exit Animation

The signal-backed queue keeps newest notifications first, and the provider's flex stack handles variable-height toast spacing. Manual dismiss changes the item status to exiting, then removes it after the animation delay.