React Inbox SDK (Web)
Drop-in React components for a fully-featured notification inbox with real-time updates, preference management, and CSS theme support.
Building a React Native app? See React Native Inbox for native mobile components with
StyleSheettheming.
Live Preview
Try the inbox components below — click the bell icon, mark notifications as read, archive, and explore the different views.
Installation
npm install @zyphr-dev/inbox-react
# or
yarn add @zyphr-dev/inbox-react
Quick Start
1. Generate a Subscriber Token (Server-Side)
The subscriber token is a JWT generated on your backend using your API key. Never expose your API key to the client.
// Express example
app.get('/api/inbox-token', async (req, res) => {
const response = await fetch('https://api.zyphr.dev/v1/subscriber-inbox/token', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.ZYPHR_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ external_id: req.user.id }),
});
const { data } = await response.json();
res.json({ token: data.token }); // data.expires_in = 604800 (7 days)
});
2. Add the Provider and Components
import { ZyphrProvider, InboxBell, InboxPopover } from '@zyphr-dev/inbox-react';
import '@zyphr-dev/inbox-react/styles.css';
function App() {
const [token, setToken] = useState('');
useEffect(() => {
fetch('/api/inbox-token')
.then(r => r.json())
.then(d => setToken(d.token));
}, []);
if (!token) return null;
return (
<ZyphrProvider subscriberToken={token}>
<InboxBell />
<InboxPopover />
</ZyphrProvider>
);
}
Provider Configuration
<ZyphrProvider
subscriberToken={token} // Required — JWT from POST /v1/subscriber-inbox/token
apiUrl="https://api.zyphr.dev" // Default
wsUrl="wss://ws.api.zyphr.dev" // Default
realtime={true} // Enable WebSocket updates (default: true)
theme="system" // 'light' | 'dark' | 'system' (default: 'system')
locale="en" // Locale for date formatting (default: 'en')
demo={false} // Demo mode with mock data (default: false)
>
{children}
</ZyphrProvider>
| Prop | Type | Default | Description |
|---|---|---|---|
subscriberToken | string | — | Required. Subscriber JWT from /v1/subscriber-inbox/token |
apiUrl | string | https://api.zyphr.dev | API endpoint |
wsUrl | string | wss://ws.api.zyphr.dev | WebSocket endpoint |
realtime | boolean | true | Enable real-time WebSocket updates |
theme | 'light' | 'dark' | 'system' | 'system' | Color scheme ('system' auto-detects, web only) |
locale | string | 'en' | Locale for date formatting |
demo | boolean | false | Render with mock data, no API calls |
Demo Mode
Use demo mode for previews and testing without API calls:
<ZyphrProvider subscriberToken="demo" demo>
<InboxBell />
<InboxPopover />
</ZyphrProvider>
Components
InboxBell
Bell icon with unread badge count.
import { InboxBell } from '@zyphr-dev/inbox-react';
<InboxBell />
InboxPopover
Dropdown notification feed triggered by clicking the bell.
import { InboxPopover } from '@zyphr-dev/inbox-react';
<InboxPopover />
InboxFeed
Full notification list with All/Unread tabs, infinite scroll, and mark-all-as-read.
import { InboxFeed } from '@zyphr-dev/inbox-react';
<InboxFeed />
| Prop | Type | Default | Description |
|---|---|---|---|
renderItem | (notification, actions) => ReactNode | — | Custom notification renderer |
className | string | — | CSS class |
NotificationItem
Renders a single notification with action buttons, priority styling, and relative timestamps.
import { NotificationItem } from '@zyphr-dev/inbox-react';
<NotificationItem
notification={notification}
onClick={() => handleClick(notification)}
/>
PreferencesPanel
Notification preference management UI.
import { PreferencesPanel } from '@zyphr-dev/inbox-react';
<PreferencesPanel />
Hooks
useInbox
Access notifications and actions:
import { useInbox } from '@zyphr-dev/inbox-react';
function CustomInbox() {
const {
notifications, // Notification[] — always an array, never undefined
unreadCount, // number
isLoading, // boolean
hasMore, // boolean — more pages available
error, // Error | null
markAsRead, // (id: string) => Promise<void>
markAllAsRead, // () => Promise<void>
archiveNotification, // (id: string) => Promise<void>
deleteNotification, // (id: string) => Promise<void>
loadMore, // () => Promise<void> — load next page
refreshNotifications, // () => Promise<void> — refresh from start
} = useInbox();
return (
<div>
<button onClick={markAllAsRead}>Mark all read</button>
{notifications.map(n => (
<div key={n.id} onClick={() => markAsRead(n.id)}>
<h3>{n.title}</h3>
<p>{n.body}</p>
</div>
))}
{hasMore && <button onClick={loadMore}>Load more</button>}
</div>
);
}
useUnreadCount
Get just the unread count:
import { useUnreadCount } from '@zyphr-dev/inbox-react';
function NavBar() {
const { unreadCount } = useUnreadCount();
return (
<nav>
<a href="/inbox">
Inbox {unreadCount > 0 && `(${unreadCount})`}
</a>
</nav>
);
}
useRealTime
WebSocket connection status:
import { useRealTime } from '@zyphr-dev/inbox-react';
function ConnectionStatus() {
const { connected } = useRealTime();
return <span>{connected ? 'Live' : 'Reconnecting...'}</span>;
}
usePreferences
Manage notification preferences:
import { usePreferences } from '@zyphr-dev/inbox-react';
function PreferencesPage() {
const { preferences, isLoading, updatePreferences } = usePreferences();
if (isLoading) return <Spinner />;
return (
<div>
{preferences?.categories.map(cat => (
<div key={cat.category.id}>
<h3>{cat.category.name}</h3>
{cat.channels.map(ch => (
<label key={ch.channel}>
<input
type="checkbox"
checked={ch.enabled}
onChange={() => updatePreferences([{
category_id: cat.category.id,
channel: ch.channel,
enabled: !ch.enabled,
}])}
/>
{ch.channel}
</label>
))}
</div>
))}
</div>
);
}
Styling
CSS Variables
:root {
--zyphr-primary: #4a90d9;
--zyphr-background: #ffffff;
--zyphr-text: #1a1a1a;
--zyphr-border: #e5e5e5;
--zyphr-unread: #e8f4fd;
--zyphr-badge: #ef4444;
}
React Native
For React Native apps, use the dedicated @zyphr-dev/inbox-react-native package which provides native components built with View, FlatList, Modal, Switch, and React Native's Appearance API.
npm install @zyphr-dev/inbox-react-native
See the React Native Inbox docs for full component API, theming, and usage examples.
Server-Side Rendering
The provider handles SSR gracefully — no DOM access during server render:
'use client';
import { ZyphrProvider, InboxBell, InboxPopover } from '@zyphr-dev/inbox-react';
import '@zyphr-dev/inbox-react/styles.css';
export function Inbox({ subscriberToken }: { subscriberToken: string }) {
return (
<ZyphrProvider subscriberToken={subscriberToken}>
<InboxBell />
<InboxPopover />
</ZyphrProvider>
);
}
TypeScript
Full TypeScript support with exported types:
import type {
Notification,
ZyphrConfig,
InboxState,
UseInboxReturn,
UseUnreadCountReturn,
} from '@zyphr-dev/inbox-react';
Requirements
- React 18.0 or later
- Modern browser (Chrome, Firefox, Safari, Edge) for web components
- React Native (Expo SDK 52+) for hooks-only usage