Skip to main content

React Inbox SDK

A drop-in notification inbox component for React applications with real-time updates.

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/inbox-react
# or
yarn add @zyphr/inbox-react

Quick Start

Finding Your Public Key

Your public key is available in the Dashboard under Applications → [Your App] → API Keys. It starts with za_pub_ and is safe to use in client-side code.

import { ZyphrInbox, ZyphrProvider } from '@zyphr/inbox-react';

function App() {
return (
<ZyphrProvider
publicKey="za_pub_your_key"
subscriberId="user_123"
>
<YourApp />
<ZyphrInbox />
</ZyphrProvider>
);
}

Provider Configuration

Wrap your app with ZyphrProvider:

<ZyphrProvider
// Required
publicKey="za_pub_your_key"
subscriberId="user_123"

// Authentication (choose one)
token="subscriber_jwt_token" // Static token
tokenEndpoint="/api/inbox-token" // Fetch token from endpoint

// Optional
baseUrl="https://api.zyphr.dev"
wsEndpoint="wss://realtime.zyphr.dev"
debug={false}
>
{children}
</ZyphrProvider>

Demo Mode

Use demo mode to render with mock data and no API or WebSocket calls — useful for previews, documentation, and testing:

<ZyphrProvider subscriberToken="demo" demo>
<ZyphrInbox />
</ZyphrProvider>

Token Authentication

For secure authentication, generate tokens server-side:

Backend
// Express endpoint
app.get('/api/inbox-token', async (req, res) => {
const token = await zyphr.inbox.createToken({
subscriberId: req.user.id,
});
res.json({ token });
});
Frontend
<ZyphrProvider
publicKey="za_pub_xxx"
subscriberId={user.id}
tokenEndpoint="/api/inbox-token"
>

Inbox Component

Basic Usage

<ZyphrInbox />

With Options

<ZyphrInbox
// Display
position="bottom-right" // "top-left" | "top-right" | "bottom-left" | "bottom-right"
theme="auto" // "light" | "dark" | "auto"
showUnreadBadge={true}
badgePosition="top-right"

// Behavior
playSound={true}
showToast={true}
closeOnOutsideClick={true}

// Limits
pageSize={25}
maxHeight="500px"

// Callbacks
onNotificationClick={(notification) => {
router.push(notification.actionUrl);
}}
onUnreadCountChange={(count) => {
document.title = count > 0 ? `(${count}) App` : 'App';
}}
onOpen={() => console.log('Inbox opened')}
onClose={() => console.log('Inbox closed')}
/>

Bell Icon

Use the default bell or your own trigger:

Default Bell

<ZyphrInbox />

Custom Trigger

<ZyphrInbox
renderTrigger={({ unreadCount, onClick }) => (
<button onClick={onClick} className="my-bell">
<BellIcon />
{unreadCount > 0 && <span>{unreadCount}</span>}
</button>
)}
/>

Hooks

useZyphrInbox

Access inbox state and methods:

import { useZyphrInbox } from '@zyphr/inbox-react';

function CustomInbox() {
const {
// State
notifications,
unreadCount,
isLoading,
hasMore,

// Actions
markAsRead,
markAllAsRead,
archive,
delete: deleteNotification,
refresh,
loadMore,
} = useZyphrInbox();

return (
<div>
<button onClick={markAllAsRead}>Mark all read</button>
{notifications.map(n => (
<NotificationItem
key={n.id}
notification={n}
onRead={() => markAsRead(n.id)}
/>
))}
{hasMore && <button onClick={loadMore}>Load more</button>}
</div>
);
}

useZyphrEvents

Listen for real-time events:

import { useZyphrEvents } from '@zyphr/inbox-react';

function NotificationToast() {
useZyphrEvents({
onNotification: (notification) => {
toast.success(notification.title);
},
onUnreadCountChange: (count) => {
// Update favicon badge, etc.
},
onConnectionChange: (connected) => {
if (!connected) {
console.warn('Realtime disconnected');
}
},
});

return null;
}

useUnreadCount

Get just the unread count:

import { useUnreadCount } from '@zyphr/inbox-react';

function NavBar() {
const unreadCount = useUnreadCount();

return (
<nav>
<a href="/inbox">
Inbox {unreadCount > 0 && `(${unreadCount})`}
</a>
</nav>
);
}

Preferences Component

Let users manage their notification preferences:

import { ZyphrPreferences } from '@zyphr/inbox-react';

function SettingsPage() {
return (
<ZyphrPreferences
categories={[
{ id: 'comments', label: 'Comments', description: 'New comments on your posts' },
{ id: 'mentions', label: 'Mentions', description: 'When someone mentions you' },
{ id: 'updates', label: 'Product Updates', description: 'New features and improvements' },
]}
onSave={(preferences) => {
console.log('Saved:', preferences);
}}
/>
);
}

Styling

CSS Variables

:root {
/* Colors */
--zyphr-primary: #4a90d9;
--zyphr-primary-hover: #3a7bc8;
--zyphr-background: #ffffff;
--zyphr-surface: #f5f5f5;
--zyphr-text: #1a1a1a;
--zyphr-text-secondary: #666666;
--zyphr-border: #e5e5e5;

/* Unread indicator */
--zyphr-unread-bg: #e8f4fd;
--zyphr-unread-dot: #4a90d9;

/* Badge */
--zyphr-badge-bg: #ef4444;
--zyphr-badge-text: #ffffff;

/* Sizing */
--zyphr-border-radius: 8px;
--zyphr-font-size: 14px;
}

/* Dark mode */
[data-theme="dark"] {
--zyphr-background: #1a1a1a;
--zyphr-surface: #2a2a2a;
--zyphr-text: #ffffff;
--zyphr-border: #333333;
}

Custom Classes

<ZyphrInbox
classNames={{
container: 'my-inbox',
trigger: 'my-trigger',
dropdown: 'my-dropdown',
notification: 'my-notification',
unread: 'my-unread',
badge: 'my-badge',
empty: 'my-empty-state',
}}
/>

Tailwind CSS

The component works great with Tailwind:

<ZyphrInbox
classNames={{
container: 'relative',
trigger: 'p-2 rounded-full hover:bg-gray-100',
dropdown: 'absolute right-0 mt-2 w-80 bg-white rounded-lg shadow-lg',
notification: 'px-4 py-3 hover:bg-gray-50 cursor-pointer',
unread: 'bg-blue-50',
}}
/>

TypeScript

Full TypeScript support:

import type {
Notification,
NotificationPreferences,
ZyphrInboxProps,
} from '@zyphr/inbox-react';

const handleClick = (notification: Notification) => {
console.log(notification.id, notification.title);
};

Server-Side Rendering

The component handles SSR gracefully:

// Next.js App Router
'use client';

import { ZyphrProvider, ZyphrInbox } from '@zyphr/inbox-react';

export function Inbox({ userId }: { userId: string }) {
return (
<ZyphrProvider publicKey="za_pub_xxx" subscriberId={userId}>
<ZyphrInbox />
</ZyphrProvider>
);
}

Requirements

  • React 18.0 or later
  • Modern browser (Chrome, Firefox, Safari, Edge)