# Prebuilt Inbox Component

This guide covers the prebuilt Notification Inbox components for an Indie Notification Inbox.

native-notify ships a prebuilt Notification Inbox: a bell icon for your app header with an unread dot, and a full-screen inbox screen that opens when the bell is tapped. In `mode="indie"` the inbox displays the current user's notifications — the same data returned by the [getIndieNotificationInbox function](/docs/indie-notification-inbox/getIndieNotificationInbox).

## Quick start

Add the `<NotificationInboxBell>` component to your header with `mode="indie"` and the user's `subId`:

```jsx
import { NotificationInboxBell } from 'native-notify';

// Expo Router / React Navigation header:
<Stack.Screen
  name="index"
  options={{
    headerRight: () => (
      <NotificationInboxBell
        appId={yourAppId}
        appToken="yourAppToken"
        mode="indie"           // or "mass" (default)
        subId={currentUser.id} // required when mode="indie"
      />
    ),
  }}
/>
```

The `subId` is the unique user ID you registered with Native Notify during the [Indie Push Notification registration process](/docs/indie-push-notifications/registration) — the component uses it to fetch that user's inbox.

`appId` and `appToken` are optional on every inbox component when you set them once with [`NativeNotify.init()` or `<NativeNotifyProvider>`](/docs/setup/installation) — pass them explicitly only if you prefer.

## Indie mode notes

- **Per-row delete is available.** Each row shows a delete button that removes only that user's notification using the [deleteIndieNotificationInbox function](/docs/indie-notification-inbox/deleteIndieNotificationInbox). The row is removed optimistically and is restored if the delete request fails.
- **Hide the delete button** by passing `allowDelete={false}`.
- **Works in Expo Go, on simulators, and on web.** Read state is tracked per user (`subId`), so the unread dot works everywhere — unlike [mass mode](/docs/mass-notification-inbox/components), which needs a real device for its push token.
- **Opening the inbox marks the fetched notifications as read**, so the unread dot clears when the inbox opens.
- **The app icon badge follows the unread count** — whenever the unread count refreshes, it is synced to the app icon badge with `Notifications.setBadgeCountAsync()`. Pass `syncBadge={false}` to opt out.

## Props

`NotificationInboxBell` accepts the following props:

| Prop                  | Type                               | Default                  | Description                                                                |
| --------------------- | ---------------------------------- | ------------------------ | -------------------------------------------------------------------------- |
| `appId`               | `number \| string`                 | —                        | Your Native Notify App ID.                                                 |
| `appToken`            | `string`                           | —                        | Your Native Notify App Token.                                              |
| `mode`                | `'mass' \| 'indie'`                | `'mass'`                 | Set to `'indie'` for per-user notifications.                               |
| `subId`               | `number \| string`                 | —                        | **Required** when `mode="indie"` (the user's unique ID).                   |
| `take`                | `number`                           | `20`                     | Number of notifications fetched per page.                                  |
| `syncBadge`           | `boolean`                          | `true`                   | Sync the unread count to the app icon badge.                               |
| `colors`              | `object`                           | light/dark theme         | Partial theme override — see [Colors](#colors).                            |
| `title`               | `string`                           | `'Notifications'`        | Inbox header title.                                                        |
| `emptyText`           | `string`                           | `"You're all caught up"` | Empty-state body text.                                                     |
| `allowDelete`         | `boolean`                          | `true`                   | Show the per-row delete button (indie mode only). Pass `false` to hide it. |
| `onNotificationPress` | `(notification) => void`           | —                        | Called when a row is tapped.                                               |
| `onOpen`              | `() => void`                       | —                        | If set, called instead of opening the built-in inbox screen.               |
| `showCount`           | `boolean`                          | `false`                  | Show a numeric unread badge instead of a plain dot.                        |
| `maxCount`            | `number`                           | `99`                     | Badge cap — shows "99+" past it.                                           |
| `renderIcon`          | `({ unreadCount, color }) => node` | bundled bell icon        | Custom bell icon.                                                          |
| `iconSize`            | `number`                           | `24`                     | Bell icon size.                                                            |
| `iconStyle`           | `StyleProp<ImageStyle>`            | —                        | Style override for the bell icon.                                          |
| `containerStyle`      | `StyleProp<ViewStyle>`             | —                        | Style override for the bell container.                                     |

### Colors

Colors follow the device's light/dark mode automatically. Pass any subset of the keys below in `colors` to override the theme:

```jsx
<NotificationInboxBell
  appId={yourAppId}
  appToken="yourAppToken"
  mode="indie"
  subId={currentUser.id}
  colors={{ dot: '#EF4444', accent: '#2563EB' }}
/>
```

- `icon`, `dot`, `badgeText`
- `background`, `headerBackground`, `card`, `border`
- `title`, `text`, `mutedText`, `emptyTitle`, `emptyText`
- `accent`, `delete`

## Custom screen and headless hook

Want your own trigger instead of the bell? Render `<NotificationInboxScreen>` and control the modal yourself with `visible` / `onClose` — it accepts all of the props above plus these:

| Prop      | Type         | Default | Description                         |
| --------- | ------------ | ------- | ----------------------------------- |
| `visible` | `boolean`    | —       | Whether the inbox modal is shown.   |
| `onClose` | `() => void` | —       | Called when the modal is dismissed. |

To build a fully custom UI, use the headless hook:

```jsx
import { useNotificationInbox } from 'native-notify';

const {
  notifications,   // fetched inbox rows
  unreadCount,     // unread count for your own badge
  loading,         // initial load in progress
  refreshing,      // pull-to-refresh in progress
  loadingMore,     // next page in progress
  hasMore,         // more pages available
  error,           // error message, if any
  openInbox,       // marks fetched notifications as read
  refresh,
  refreshUnread,
  loadMore,
  deleteNotification, // per-row delete (indie mode)
} = useNotificationInbox({
  appId: yourAppId,
  appToken: 'yourAppToken',
  mode: 'indie',
  subId: currentUser.id, // required when mode: 'indie'
  take: 20,
  syncBadge: true, // sync the unread count to the app icon badge
});
```

Exact pagination is available for custom UIs: [`getIndieNotificationInboxPage()`](/docs/indie-notification-inbox/getIndieNotificationInbox) returns `{ rows, total }` — the server's `X-Total-Count` — so "load more" is exact instead of a guess.

## Inbox row data

Each row in the inbox is shaped like this:

```jsx
{
  notification_id, // unique notification ID — used for deletes
  date,            // notification date
  title,           // notification title
  message,         // notification message
  pushData,        // data object sent with the push notification
}
```
