Container for displaying a list of notifications with empty states and loading skeletons
Tags: component notification list container
Container component for displaying a list of notifications. Handles empty states, loading skeletons, and renders NotificationItem components.
Import
Notification components are available via a separate entry point to make @classic-homes/notifications an optional dependency.
<script>
import { NotificationList } from '@classic-homes/theme-svelte/notifications';
</script>Note: Using notification components requires
@classic-homes/notificationsto be installed.
Basic Usage
<script>
import type { Notification } from '@classic-homes/notifications/core';
let notifications = $state<Notification[]>([
// ... notification objects
]);
</script>
<NotificationList {notifications} />Props
| Prop | Type | Default | Description |
|---|---|---|---|
notifications |
Notification[] |
required | List of notifications to display |
selectedIds |
Set<string> |
new Set() |
Set of selected notification IDs |
selectable |
boolean |
false |
Whether selection mode is enabled |
onToggleSelect |
(id: string, selected: boolean) => void |
- | Callback when a notification's selection changes |
onNotificationClick |
(notification: Notification) => void |
- | Callback when a notification is clicked |
emptyState |
Snippet |
- | Custom empty state snippet |
emptyTitle |
string |
'No notifications' |
Empty state title |
emptyDescription |
string |
"You're all caught up!" |
Empty state description |
loading |
boolean |
false |
Whether the list is loading |
class |
string |
- | Additional CSS classes |
Empty State
The default empty state shows a bell-off icon with customizable text:
<NotificationList
notifications={[]}
emptyTitle="No unread notifications"
emptyDescription="All caught up!"
/>Custom Empty State
Provide a completely custom empty state:
<NotificationList notifications={[]}>
{#snippet emptyState()}
<div class="text-center py-12">
<img src="/empty-inbox.svg" alt="" class="mx-auto mb-4" />
<h3 class="text-lg font-medium">Inbox Zero!</h3>
<p class="text-muted-foreground">You have no notifications</p>
</div>
{/snippet}
</NotificationList>Loading State
Show skeleton placeholders while loading:
<NotificationList notifications={[]} loading={true} />The loading state displays 3 animated skeleton items.
Selection Mode
Enable selection for bulk operations:
<script>
let selectedIds = $state(new Set<string>());
function handleToggleSelect(id: string, selected: boolean) {
const newSet = new Set(selectedIds);
if (selected) {
newSet.add(id);
} else {
newSet.delete(id);
}
selectedIds = newSet;
}
</script>
<NotificationList
{notifications}
{selectedIds}
selectable={true}
onToggleSelect={handleToggleSelect}
/>Click Handler
Handle notification clicks to show details:
<script>
let selectedNotification = $state<Notification | null>(null);
let dialogOpen = $state(false);
function handleNotificationClick(notification: Notification) {
selectedNotification = notification;
dialogOpen = true;
}
</script>
<NotificationList {notifications} onNotificationClick={handleNotificationClick} />
<NotificationDialog notification={selectedNotification} bind:open={dialogOpen} />Examples
Complete Notification Center
<script>
import {
NotificationList,
NotificationFilters,
NotificationBulkActions,
NotificationDialog,
} from '@classic-homes/theme-svelte/notifications';
import type { Notification, NotificationFilter, NotificationCounts } from '@classic-homes/notifications/core';
let notifications = $state<Notification[]>([...]);
let filter = $state<NotificationFilter>('all');
let selectedIds = $state(new Set<string>());
let dialogOpen = $state(false);
let selectedNotification = $state<Notification | null>(null);
const filteredNotifications = $derived(() => {
switch (filter) {
case 'unread': return notifications.filter(n => !n.read);
case 'read': return notifications.filter(n => n.read);
default: return notifications;
}
});
const counts: NotificationCounts = $derived({
all: notifications.length,
unread: notifications.filter(n => !n.read).length,
read: notifications.filter(n => n.read).length,
});
</script>
<NotificationFilters bind:filter {counts} />
<NotificationBulkActions
selectedCount={selectedIds.size}
totalCount={filteredNotifications().length}
onSelectAll={(selected) => {
/* ... */
}}
onMarkRead={() => {
/* ... */
}}
onDelete={() => {
/* ... */
}}
/>
<NotificationList
notifications={filteredNotifications()}
{selectedIds}
selectable={true}
onToggleSelect={handleToggleSelect}
onNotificationClick={handleNotificationClick}
/>
<NotificationDialog notification={selectedNotification} bind:open={dialogOpen} />With Filter-Specific Empty States
<NotificationList
notifications={filteredNotifications()}
emptyTitle={filter === 'unread'
? 'No unread notifications'
: filter === 'read'
? 'No read notifications'
: 'No notifications'}
emptyDescription={filter === 'unread'
? 'All caught up!'
: filter === 'read'
? 'No notifications have been read yet'
: "You're all caught up!"}
/>Related Components
- NotificationItem - Single notification card
- NotificationFilters - Filter tabs
- NotificationBulkActions - Bulk action toolbar
- NotificationDialog - Notification details modal