<img width="1040" alt="courier-ui-inbox" src="https://github.com/user-attachments/assets/6227249b-d008-4719-bddc-874f34432376" />

## 1. Install

```sh
npm install @trycourier/courier-ui-inbox
```

> **Using React?** We suggest you use [@trycourier/courier-react](../courier-react/README.md) package instead.

## 2. Authenticate

To use the SDK, you need to generate a JWT (JSON Web Token) for your user. **This JWT should always be generated by your backend server, never in client-side code.**

**How it works:**

1. **Your frontend calls your backend:**
   - When your app needs to authenticate a user, your frontend should make a request to your own backend (e.g., `/api/generate-courier-jwt`).

2. **Your backend calls Courier to issue a JWT:**
   - In your backend endpoint, use your [Courier API Key](https://app.courier.com/settings/api-keys) to call the [Courier JWT Token Endpoint](https://www.courier.com/docs/reference/auth/issue-token) and generate a JWT for the user.
   - Your backend then returns the JWT to your frontend.

To quickly test JWT generation (for development only), you can use the following cURL command to call Courier's API directly. **Do not use this in production or from client-side code.**

```sh
curl --request POST \
     --url https://api.courier.com/auth/issue-token \
     --header 'Accept: application/json' \
     --header 'Authorization: Bearer $YOUR_API_KEY' \
     --header 'Content-Type: application/json' \
     --data \
 '{
    "scope": "user_id:$YOUR_USER_ID write:user-tokens inbox:read:messages inbox:write:events read:preferences write:preferences read:brands",
    "expires_in": "$YOUR_NUMBER days"
  }'
```

## 3. Add Inbox Component

### `courier-inbox`

<img width="688" alt="Screenshot 2025-06-25 at 2 32 30 PM" src="https://github.com/user-attachments/assets/93246c34-3c5a-475e-8e83-7df6acf9bdf3" />

```html
<body>

  <courier-inbox id="inbox"></courier-inbox>

  <script type="module">
    import { Courier } from '@trycourier/courier-ui-inbox';

    // Generate a JWT for your user (do this on your backend server)
    const jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'; // Replace with actual JWT

    // Authenticate the user with the inbox
    Courier.shared.signIn({
      userId: $YOUR_USER_ID,
      jwt: jwt
    });
  </script>

</body>
```

### `courier-inbox-popup-menu`

<img width="602" alt="Screenshot 2025-06-25 at 2 33 17 PM" src="https://github.com/user-attachments/assets/c3b7f4cc-26c1-4be6-9ed5-a3fc3c0b335b" />

```html
<body>

  <div style="padding: 24px;">
    <courier-inbox-popup-menu id="inbox"></courier-inbox-popup-menu>
  </div>

  <script type="module">
    import { Courier } from '@trycourier/courier-ui-inbox';

    // Generate a JWT for your user (do this on your backend server)
    const jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'; // Replace with actual JWT

    // Authenticate the user with the inbox
    Courier.shared.signIn({
      userId: $YOUR_USER_ID,
      jwt: jwt
    });
  </script>

</body>
```

## Handle Clicks and Presses

```html
<body>

  <courier-inbox id="inbox"></courier-inbox> <!-- or use courier-inbox-popup-menu -->

  <script type="module">
    import { Courier } from '@trycourier/courier-ui-inbox';

    // Generate a JWT for your user (do this on your backend server)
    const jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...'; // Replace with actual JWT

    // Authenticate the user with the inbox
    Courier.shared.signIn({
      userId: $YOUR_USER_ID,
      jwt: jwt
    });

    // Reference the element
    const inbox = document.getElementById('inbox');

    // Handle message clicks
    inbox.onMessageClick(({ message, index }) => {
      alert("Message clicked at index " + index + ":\n" + JSON.stringify(message, null, 2));
    });

    // Handle message action clicks (These are buttons on individial messages)
    inbox.onMessageActionClick(({ message, action, index }) => {
      alert(
        "Message action clicked at index " + index + ":\n" +
        "Action: " + JSON.stringify(action, null, 2) + "\n" +
        "Message: " + JSON.stringify(message, null, 2)
      );
    });

    // Handle message long presses. **Only works on devices that support javascript's touch events. This will not work with a mouse cursor.**
    inbox.onMessageLongPress(({ message, index }) => {
      alert("Message long pressed at index " + index + ":\n" + JSON.stringify(message, null, 2));
    });
  </script>

</body>
```

## Styles and Theming

### Light & Dark Themes

The fastest way to style the Inbox to match your app. This example shows unread indicator styling, but you can customize fonts, icons, text, and more.

> **🎨 Theme Reference:** [All available theme values](./docs/theme.md)

<img width="688" alt="Screenshot 2025-06-25 at 2 36 20 PM" src="https://github.com/user-attachments/assets/982164fe-fe0d-4e66-82d1-b5a6571f1aa4" />

```html
<body>

  <courier-inbox id="inbox"></courier-inbox> <!-- or use courier-inbox-popup-menu -->

  <script type="module">
    ...

    // Reference the element
    const inbox = document.getElementById('inbox');

    const theme = {
      inbox: {
        header: {
          filters: {
            unreadIndicator: {
              backgroundColor: "#8B5CF6"
            }
          }
        },
        list: {
          item: {
            unreadIndicatorColor: "#8B5CF6"
          }
        }
      }
    }

    // Set the theme
    inbox.setLightTheme(theme);
    inbox.setDarkTheme(theme);

    // Set the mode
    // This will force light, dark or system theme mode
    inbox.setMode('light');

  </script>

</body>
```

### Popup Alignment, Positioning, and Dimensions

```html
<body>

  <div style="display: flex; justify-content: center; align-items: center; padding: 100px;">
    <!-- Available alignments: 'top-right' | 'top-left' | 'top-center' | 'bottom-right' | 'bottom-left' | 'bottom-center' | 'center-right' | 'center-left' | 'center-center' -->
    <courier-inbox-popup-menu
      popup-alignment="top-right"
      top="44px"
      right="44px"
      popup-width="340px"
      popup-height="400px">
    </courier-inbox-popup-menu>
  </div>

  ...
</body>
```

### Custom height `courier-inbox`

> **Important:** The default `courier-inbox` height is auto. It will set it's height based on it's children.

```html
<body>

  <courier-inbox height="50vh"></courier-inbox>

  ...

</body>
```

## Custom Elements

Customize the inbox UI with any element you want.

### List Items

<img width="688" alt="Screenshot 2025-06-25 at 2 37 29 PM" src="https://github.com/user-attachments/assets/53da26d1-ed9a-461d-ad92-2e74ee3e91bf" />

```html
<body>

  <courier-inbox id="inbox"></courier-inbox> <!-- or use courier-inbox-popup-menu -->

  <script type="module">
    ...

    // Reference the courier-inbox element
    const inbox = document.getElementById('inbox');

    // Set a custom list item
    inbox.setListItem(({ message, index }) => {
      const pre = document.createElement('pre');
      pre.style.padding = '24px';
      pre.style.borderBottom = '1px solid #e0e0e0';
      pre.style.margin = '0';
      pre.textContent = JSON.stringify(({ message, index }), null, 2);
      return pre;
    });
  </script>

</body>
```

### Header

<img width="688" alt="Screenshot 2025-06-25 at 2 38 45 PM" src="https://github.com/user-attachments/assets/d393f77d-695e-4fed-a60a-7f7b59909772" />

```html
<body>

  <courier-inbox id="inbox"></courier-inbox> <!-- or use courier-inbox-popup-menu -->

  <script type="module">
    ...

    // Reference the courier-inbox element
    const inbox = document.getElementById('inbox');

    // Remove the header
    inbox.removeHeader();

    // Set a custom header
    inbox.setHeader(({ feedType, unreadCount, messageCount }) => {
      const headerDiv = document.createElement('div');
      headerDiv.style.background = 'red';
      headerDiv.style.fontSize = '24px';
      headerDiv.style.padding = '24px';
      headerDiv.style.width = '100%';
      headerDiv.textContent = feedType;
      return headerDiv;
    });

    // Change the feed type
    // "inbox" and "archive" are available
    inbox.setFeedType('archive');
  </script>

</body>
```

### Popup Menu Button

<img width="688" alt="Screenshot 2025-06-25 at 2 39 49 PM" src="https://github.com/user-attachments/assets/5eeb32ae-13ff-4622-b6ea-b302f04509f3" />

```html
<body>

  <div style="display: flex; justify-content: center; align-items: center; padding: 100px;">
    <courier-inbox-popup-menu id="inbox"></courier-inbox-popup-menu>
  </div>

  <script type="module">
    ...

    // Reference the courier-inbox element
    const inbox = document.getElementById('inbox');

    // Set a custom menu button
    inbox.setMenuButton(({ unreadCount }) => {
      const button = document.createElement('button');
      button.textContent = `Open the Inbox Popup. Unread message count: ${unreadCount}`;
      return button;
    });
  </script>

</body>
```

### Loading, Empty, Error & Pagination

```html
<body>

  <courier-inbox id="inbox"></courier-inbox> <!-- or use courier-inbox-popup-menu -->

  <script type="module">
    ...

    // Reference the courier-inbox element
    const inbox = document.getElementById('inbox');

    // Set a custom loading state
    inbox.setLoadingState(props => {
      const loading = document.createElement('div');
      loading.style.padding = '24px';
      loading.style.background = 'red';
      loading.textContent = 'Custom Loading State';
      return loading;
    });

    // Set a custom empty state
    inbox.setEmptyState(props => {
      const empty = document.createElement('div');
      empty.style.padding = '24px';
      empty.style.background = 'green';
      empty.textContent = 'Custom Empty State';
      return empty;
    });

    // Set a custom error state
    inbox.setErrorState(props => {
      const error = document.createElement('div');
      error.style.padding = '24px';
      error.style.background = 'blue';
      error.textContent = 'Custom Error State';
      return error;
    });

    // Set a custom pagination state
    inbox.setPaginationItem(props => {
      const pagination = document.createElement('div');
      pagination.style.padding = '24px';
      pagination.style.background = 'yellow';
      pagination.textContent = 'Custom Pagination Item';
      return pagination;
    });
  </script>

</body>
```

> **Using React?** We suggest you use [@trycourier/courier-react](../courier-react/README.md) package instead.

# **Share feedback with Courier**

We want to make this the best SDK for managing notifications! Have an idea or feedback about our SDKs? Let us know!

[Courier Web Issues](https://github.com/trycourier/courier-web/issues)
