Skip to main content

React Native Inbox SDK

Native React Native components for a fully-featured notification inbox with real-time updates, preference management, and built-in light/dark theme support.

Looking for the web version? See React Inbox for React DOM components with CSS styling.

Installation​

npm install @zyphr-dev/inbox-react-native
# or
yarn add @zyphr-dev/inbox-react-native

Peer dependencies: react >= 17.0.0, react-native >= 0.64.0

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.

Your backend
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 });
});

2. Add the Provider and Components​

App.tsx
import { ZyphrProvider, InboxPopover } from '@zyphr-dev/inbox-react-native';

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}>
<Navigation />
</ZyphrProvider>
);
}

No CSS import needed -- styling is handled via StyleSheet and the theme context.

Provider Configuration​

<ZyphrProvider
subscriberToken={token} // Required
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>
PropTypeDefaultDescription
subscriberTokenstring--Required. Subscriber JWT from /v1/subscriber-inbox/token
apiUrlstringhttps://api.zyphr.devAPI endpoint
wsUrlstringwss://ws.api.zyphr.devWebSocket endpoint
realtimebooleantrueEnable real-time WebSocket updates
theme'light' | 'dark' | 'system''system'Color scheme (uses RN Appearance API)
localestring'en'Locale for date formatting
demobooleanfalseRender with mock data, no API calls
Theme Detection

Unlike the web version, 'system' theme uses React Native's Appearance API, which works natively on both iOS and Android without DOM access.

Components​

InboxBell​

Bell icon button with unread count badge.

import { InboxBell } from '@zyphr-dev/inbox-react-native';

<InboxBell onPress={() => navigation.navigate('Inbox')} />
<InboxBell dot />
<InboxBell size={48} maxCount={50} />
PropTypeDefaultDescription
onPress() => void--Press handler
styleViewStyle--Container style
dotbooleanfalseShow dot instead of count
maxCountnumber99Maximum display count (e.g., 99+)
bellIconReactNode--Custom bell icon element
sizenumber40Button size in points

InboxPopover​

Modal-based notification feed triggered by clicking the bell.

import { InboxPopover } from '@zyphr-dev/inbox-react-native';

// Uncontrolled (manages own visibility)
<InboxPopover />

// Controlled
<InboxPopover
visible={isOpen}
onVisibilityChange={setIsOpen}
animationType="fade"
/>

// Custom trigger
<InboxPopover trigger={<MyCustomButton />} />
PropTypeDefaultDescription
visibleboolean--Controlled visibility
onVisibilityChange(visible: boolean) => void--Visibility callback
styleViewStyle--Modal content style
categoriesstring[]--Filter by categories
triggerReactNode--Custom trigger element
animationType'slide' | 'fade' | 'none''slide'Modal animation
presentationStylestring'pageSheet'iOS modal presentation style

InboxFeed​

Full notification list with All/Unread tabs, pull-to-refresh, and infinite scroll via FlatList.

import { InboxFeed } from '@zyphr-dev/inbox-react-native';

<InboxFeed />
<InboxFeed categories={['alerts', 'updates']} />
PropTypeDefaultDescription
categoriesstring[]--Filter by categories
styleViewStyle--Container style
showArchivedbooleanfalseInclude archived notifications
emptyStateReactNode--Custom empty state component
renderItem(notification, actions) => ReactNode--Custom notification renderer

NotificationItem​

Renders a single notification with priority styling, relative timestamps, and action buttons.

import { NotificationItem } from '@zyphr-dev/inbox-react-native';

<NotificationItem
notification={notification}
onPress={() => handlePress(notification)}
/>

PreferencesPanel​

ScrollView-based notification preference management with native Switch toggles.

import { PreferencesPanel } from '@zyphr-dev/inbox-react-native';

<PreferencesPanel
onSave={() => Alert.alert('Saved!')}
onError={(err) => Alert.alert('Error', err.message)}
/>
PropTypeDefaultDescription
styleViewStyle--Container style
showGlobalPreferencesbooleantrueShow global preferences section
channelLabelsRecord<string, string>--Custom channel labels
onSave() => void--Save success callback
onError(error: Error) => void--Error callback
saveButtonTextstring'Save Preferences'Custom button text
channelsNotificationChannel[]--Filter to specific channels

Hooks​

All hooks share the same API as the web version -- only the import path changes.

useInbox​

import { useInbox } from '@zyphr-dev/inbox-react-native';

function NotificationScreen() {
const {
notifications, unreadCount, isLoading, hasMore, error,
markAsRead, markAllAsRead, archive, delete: remove, loadMore, refresh,
} = useInbox();

return (
<FlatList
data={notifications}
renderItem={({ item }) => (
<Pressable onPress={() => markAsRead(item.id)}>
<Text style={{ fontWeight: item.read_at ? 'normal' : 'bold' }}>
{item.title}
</Text>
</Pressable>
)}
onEndReached={() => hasMore && loadMore()}
onRefresh={refresh}
refreshing={isLoading}
/>
);
}

useUnreadCount​

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

function TabBadge() {
const { count } = useUnreadCount();
if (count === 0) return null;
return <View style={styles.badge}><Text>{count}</Text></View>;
}

useRealTime​

import { useRealTime } from '@zyphr-dev/inbox-react-native';

function ConnectionIndicator() {
const { connected } = useRealTime();
return (
<View style={{
backgroundColor: connected ? '#22c55e' : '#ef4444',
width: 8, height: 8, borderRadius: 4,
}} />
);
}

usePreferences​

import { usePreferences } from '@zyphr-dev/inbox-react-native';

function CustomPreferences() {
const { preferences, updatePreference, savePreferences, hasChanges } = usePreferences();
// Build your own preference UI using the data
}

Theming​

Using the Theme Hook​

Access the current theme anywhere inside the provider:

import { useZyphrTheme } from '@zyphr-dev/inbox-react-native';

function CustomComponent() {
const theme = useZyphrTheme();

return (
<View style={{ backgroundColor: theme.colors.background, padding: theme.spacing.lg }}>
<Text style={{ color: theme.colors.text, fontSize: theme.fontSize.md }}>
Styled with Zyphr theme
</Text>
</View>
);
}

Theme Structure​

interface ZyphrTheme {
colors: {
primary, primaryHover, primarySubtle,
background, backgroundSecondary, backgroundHover,
text, textSecondary, textMuted,
border, borderSubtle,
danger, dangerHover, success, warning, urgent, unreadDot,
skeletonBase, skeletonShine,
};
spacing: { xs: 4, sm: 8, md: 12, lg: 16, xl: 24 };
borderRadius: { sm: 6, md: 10, lg: 14 };
fontSize: { xs: 11, sm: 13, md: 15, lg: 17, xl: 20 };
}

Accessing Color Palettes​

import { LIGHT_COLORS, DARK_COLORS } from '@zyphr-dev/inbox-react-native';

Comparison with Web Version​

FeatureWeb (@zyphr-dev/inbox-react)React Native (@zyphr-dev/inbox-react-native)
StylingCSS + CSS variablesStyleSheet + theme context
PopoverPositioned div + backdropModal component
Infinite scrollIntersectionObserverFlatList.onEndReached
Pull to refreshNot built-inFlatList.onRefresh
Linkswindow.open()Linking.openURL()
Theme detectionwindow.matchMedia()Appearance API
TogglesCustom CSS checkboxNative Switch
Focus trapDOM focus managementNative modal handles it
IconsInline SVGUnicode (customizable via props)
CSS importRequired (styles.css)Not needed

TypeScript​

Full TypeScript support with exported types:

import type {
Notification,
ZyphrConfig,
ZyphrTheme,
ZyphrThemeColors,
UseInboxReturn,
UseUnreadCountReturn,
UseRealTimeReturn,
UsePreferencesReturn,
} from '@zyphr-dev/inbox-react-native';

Requirements​

  • React Native 0.64+ (for Intl.RelativeTimeFormat support)
  • Expo SDK 52+ (if using Expo)
  • iOS 13+ / Android API 24+