# Notification Stack URL: /docs/web/components/notification-stack A stacked notification card system with swipe-to-dismiss gestures, auto-pagination, action buttons, and animated transitions. **Demo:** ```tsx 'use client'; import { useCallback, useState } from 'react'; import { type NotificationItem, NotificationStack } from '@docyrus/ui/components/notification-stack'; import { ArrowRight, ArrowUpRight, Check, Info, MessageSquare, Receipt, Rocket, X } from 'lucide-react'; function createNotifications(startId: number): NotificationItem[] { return [ { id: `${startId}`, type: 'comment', variant: 'unread', icon: 'OA', badge: , title: ( <> Oguz Aksu commented on Project Alpha ), content: (
"Let's review the Q3 roadmap before the sprint planning session next week."
), timestamp: '2m ago', showUnreadIndicator: true, actions: [{ label: 'Reply', variant: 'default' }, { label: 'View Thread', variant: 'link', icon: }] }, { id: `${startId + 1}`, type: 'approval', variant: 'unread', icon: , title: 'Expense Approval for Q3 Travel', subtitle: ( <> Requested by Sarah Jenkins • $1,240.50 ), timestamp: '1h ago', showUnreadIndicator: true, actions: [{ label: 'Approve', variant: 'primary', icon: }, { label: 'Deny', variant: 'danger', icon: }] }, { id: `${startId + 2}`, type: 'status', variant: 'default', icon: , title: 'Update status for Project Apollo', subtitle: 'Weekly check-in required for the enterprise deal.', timestamp: '3h ago', actions: [{ label: 'Update Status', variant: 'default' }, { label: 'View Project', variant: 'link', icon: }] }, { id: `${startId + 3}`, type: 'info', variant: 'default', icon: , title: 'New workspace features available', subtitle: 'Enhanced dashboard analytics and team collaboration tools are now live.', timestamp: '1d ago' }, { id: `${startId + 4}`, type: 'success', variant: 'default', icon: , title: 'Deployment succeeded', subtitle: 'Production release v2.4.1 deployed successfully.', timestamp: '2d ago' } ]; } export function NotificationStackDemo() { const [notifications, setNotifications] = useState( () => createNotifications(1) ); const [nextId, setNextId] = useState(6); const handleLoadMore = useCallback(() => { const newNotifications = createNotifications(nextId); setNotifications(prev => [...prev, ...newNotifications]); setNextId(prev => prev + 5); }, [nextId]); return (
{ console.info(`Dismissed: ${id}`); }} onClick={(id) => { console.info(`Clicked: ${id}`); }} onAction={(id, action) => { console.info(`Action: ${id} - ${action}`); setNotifications(prev => prev.filter(n => n.id !== id)); }} />
); } ``` ## Installation ```bash pnpm dlx @docyrus/cli add @docyrus/ui-notification-stack ``` **Dependencies:** - [lucide-react](https://www.npmjs.com/package/lucide-react) - [motion](https://www.npmjs.com/package/motion) - [@emotion/is-prop-valid](https://www.npmjs.com/package/@emotion/is-prop-valid) - [class-variance-authority](https://www.npmjs.com/package/class-variance-authority) ## Usage ```tsx import { NotificationStack } from '@docyrus/ui/components/notification-stack'; import type { NotificationItem } from '@docyrus/ui/components/notification-stack'; const notifications: NotificationItem[] = [ { id: '1', type: 'success', title: 'Deployment complete', message: 'Your app has been deployed successfully.', actions: [{ label: 'View' }] }, { id: '2', type: 'warning', title: 'Storage warning', message: 'You are using 90% of your storage quota.' }, { id: '3', type: 'info', title: 'New feature', message: 'Dark mode is now available in settings.', variant: 'unread' } ]; console.log('dismissed', id)} onClick={(id) => console.log('clicked', id)} onAction={(id, action) => console.log('action', id, action)} /> ``` ### With Pagination & Load More ```tsx fetchMoreNotifications()} onDismiss={handleDismiss} emptyState={

No notifications

} /> ``` ## Variants | Variant | Description | |---------|-------------| | `default` | Standard notification cards. | | `bordered` | Cards with enhanced shadow (`shadow-md`). | ## Sizes | Size | Description | |------|-------------| | `sm` | Compact padding and smaller text. | | `default` | Standard sizing. | | `lg` | Larger padding and text. | ## Components | Component | Description | |-----------|-------------| | `NotificationStack` | Main container. Manages stacking, pagination, and dismissed state. | | `NotificationStackCard` | Individual notification card with swipe-to-dismiss gesture. | ## API Reference ### NotificationStack | Prop | Type | Default | Description | |------|------|---------|-------------| | `notifications` | `NotificationItem[]` | — | Array of notification items to display. | | `maxVisible` | `number` | `10` | Maximum number of visible cards before pagination. | | `loadMoreThreshold` | `number` | `2` | When remaining count reaches this threshold, `onLoadMore` is triggered. | | `onLoadMore` | `() => void` | — | Called when more notifications should be fetched. | | `onDismiss` | `(id: string) => void` | — | Called when a notification is swiped away. | | `onClick` | `(id: string) => void` | — | Called when a notification card is clicked. | | `onAction` | `(id: string, action: string) => void` | — | Called when an action button is clicked. | | `variant` | `'default' \| 'bordered'` | `'default'` | Visual style. | | `size` | `'sm' \| 'default' \| 'lg'` | `'default'` | Card sizing. | | `emptyState` | `ReactNode` | — | Content shown when no notifications exist. | | `className` | `string` | — | Additional CSS classes. | ## Type Reference ### NotificationItem | Field | Type | Description | |-------|------|-------------| | `id` | `string` | Unique identifier. | | `type` | `'default' \| 'success' \| 'warning' \| 'error' \| 'info'` | Notification type (determines icon and color). | | `title` | `string` | Notification title. | | `message` | `string` | Notification body text. | | `icon` | `ReactNode \| string` | Custom icon override. | | `badge` | `ReactNode` | Badge content displayed alongside the notification. | | `actions` | `Array<{ label: string; onClick?: () => void }>` | Action buttons displayed at the bottom. | | `variant` | `'default' \| 'unread' \| 'highlighted'` | Visual variant for the individual card. | ### Interaction Details - **Swipe to dismiss**: Drag horizontally past 100px or at 500px/s velocity. - **Stacking**: Cards stack with scale reduction (5% per level) and vertical offset (10px per level). - **Pointer events**: Only the top card is interactive; stacked cards below are visual-only. - **Auto-dismiss on action**: Cards are dismissed after an action button click.