Skip to main content
Inbox UI Preview The Courier Web Components SDK provides drop-in components for building notification experiences in any JavaScript project:
  • <courier-inbox> — full-featured inbox for displaying and managing messages
  • <courier-inbox-popup-menu> — popup menu version of the inbox
  • <courier-toast> — toast notifications for time-sensitive alerts
This is the latest version of the Courier Web Components SDK, recommended for new and existing apps.Coming from an earlier version? We recommend upgrading — check out the migration guide for the React SDK, which is a thin wrapper around these Web Components and exposes a similar API.

Installation

Inbox and Toast are published as separate packages. Install one or both depending on your needs.
npm install @trycourier/courier-ui-inbox @trycourier/courier-ui-toast
Available on GitHub and npm: Inbox · Inbox · Toast · Toast The Courier SDKs work with any JavaScript build system and do not require any additional build configuration.
Using React? Check out the Courier React SDK, which provides React components and hooks built on top of these Web Components.

Authentication

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.
Inbox and Toast share the same Courier.shared authentication instance and connection to the Courier backend. Authenticate once and both components work.

JWT Authentication Flow
1

Your client calls your backend

When your app needs to authenticate a user, your client should make a request to your own backend (ex. GET https://your-awesome-app.com/api/generate-courier-jwt).
2

Your backend calls Courier

In your backend endpoint, use your Courier API Key to call the Courier Issue Token Endpoint and generate a JWT for the user.
3

Your backend returns the JWT to your client

Having received the JWT from Courier, your backend should return it to your client and pass it to the Courier SDK.
See all available user scopes for the Courier APIs.

Development Authentication with cURL To quickly test JWT generation for development only, you can use cURL to call the Courier Issue Token Endpoint directly.
Do not call the Issue Token API from client-side code. Always keep your Courier API keys secure.
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"
  }'

Inbox Web Components


<courier-inbox>
Default Courier Inbox component
Importing the Courier SDK registers Courier’s Web Components (<courier-inbox>, <courier-inbox-popup-menu>).
<body>
  <courier-inbox id="inbox"></courier-inbox>

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

    // Generate a JWT for your user on your backend server
    const jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';

    // Authenticate the user with the inbox
    Courier.shared.signIn({
      userId: $YOUR_USER_ID,
      jwt: jwt
    });
  </script>
</body>
Sample App: See a complete working example in our Vanilla JS Inbox sample app.
If you’re using tenants, you can scope requests to a particular tenant by passing its ID to the signIn request.
Courier.shared.signIn({
  userId: "my-user-id",
  jwt: jwt,
  tenantId: "my-tenant-id"
});
For the full reference of sign in parameters, see the Courier JS docs.

<courier-inbox-popup-menu>
Default Courier Inbox Popup Menu component
<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 on your backend server
    const jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';

    // Authenticate the user with the inbox
    Courier.shared.signIn({
      userId: $YOUR_USER_ID,
      jwt: jwt
    });
  </script>
</body>
Sample App: See a complete working example in our Vanilla JS Popup Menu sample app.

Tabs and Feeds Tabs and feeds allow you to organize and filter messages in your inbox. A feed is a container that groups related tabs together. Each tab represents a filtered view of messages.
If there is only one feed, the feed selection dropdown is hidden. If a feed has only one tab, the tab bar is hidden and the unread count appears next to the feed.
Filter PropertyTypeDescription
tagsstring[]Messages that have any of the specified tags
archivedbooleanWhether to include archived messages (defaults to false if unset)
status'read' | 'unread'Filter by read/unread status
Preview of CourierInbox with tabs
<body>
  <courier-inbox id="inbox"></courier-inbox>

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

    const inbox = document.getElementById('inbox');

    // Set feeds with multiple tabs
    inbox.setFeeds([
      {
        feedId: 'notifications',
        title: 'Notifications',
        tabs: [
          {
            datasetId: 'all-notifications',
            title: 'All',
            filter: {}
          },
          {
            datasetId: 'unread-notifications',
            title: 'Unread',
            filter: { status: 'unread' }
          },
          {
            datasetId: 'important',
            title: 'Important',
            filter: { tags: ['important'] }
          },
          {
            datasetId: 'archived',
            title: 'Archived',
            filter: { archived: true }
          }
        ]
      }
    ]);

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

Handle Clicks and Presses Use the onMessageClick(), onMessageActionClick(), and onMessageLongPress() methods to handle clicks and presses in the inbox.
onMessageLongPress() is only applicable on devices that support touch events.
<body>
  <courier-inbox id="inbox"></courier-inbox>

  <!-- Uncomment the line below to use the popup menu instead -->
  <!-- <courier-inbox-popup-menu id="inbox"></courier-inbox-popup-menu> -->

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

    // Generate a JWT for your user on your backend server
    const jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...';

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

    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 individual 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 (useful for mobile web)
    inbox.onMessageLongPress(({ message, index }) => {
      alert("Message long pressed at index " + index +
            ":\n" + JSON.stringify(message, null, 2));
    });
  </script>
</body>

Styles and Theming The fastest way to style the Courier Inbox to match your app is with a custom theme.
You can customize fonts, icons, text, and more. Check out the CourierInboxTheme reference.
Courier Inbox with a custom unread indicator style
<body>
  <courier-inbox id="inbox"></courier-inbox>

  <!-- Uncomment the line below to use the popup menu instead -->
  <!-- <courier-inbox-popup-menu id="inbox"></courier-inbox-popup-menu> -->

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

    // Courier authentication...

    const inbox = document.getElementById('inbox');
    const theme = {
      inbox: {
        header: {
          filters: {
            unreadIndicator: {
              backgroundColor: "#8B5CF6"
            }
          }
        },
        list: {
          item: {
            unreadIndicatorColor: "#8B5CF6"
          }
        }
      }
    };

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

    // Set the mode ('light', 'dark', or 'system')
    inbox.setMode('light');
  </script>
</body>
Popup alignment, position, and dimensions
Customizing the popup menu's alignment, position, and dimensions
Vertical AlignmentOptions
Top"top-right", "top-center", "top-left"
Center"center-right", "center-center", "center-left"
Bottom"bottom-right", "bottom-center", "bottom-left"
<body>
  <div style="display: flex; justify-content: center; align-items: center; padding: 100px;">

    <courier-inbox-popup-menu
      popup-alignment="top-right"
      top="44px"
      right="44px"
      popup-width="340px"
      popup-height="400px">
    </courier-inbox-popup-menu>
  </div>
</body>
Fixed height: <courier-inbox> has a default height of auto. Set a fixed height with the height attribute:
<body>
  <courier-inbox height="50vh"></courier-inbox>
</body>

Custom Elements Customize individual parts of the inbox by passing factory functions that return HTML elements.
Programmatic Control The <courier-inbox> component exposes methods for programmatic control, allowing you to dynamically manage feeds, tabs, actions, and data refresh. Feed and Tab Selection
MethodDescription
selectFeed(feedId)Switch to the specified feed and load its data.
selectTab(tabId)Switch to the specified tab within the current feed.
getFeeds()Returns the current array of configured feeds.
currentFeedId (getter)Returns the ID of the currently selected feed.
refresh()Forces a reload of inbox data, bypassing the cache. Returns Promise<void>.
Header Actions
MethodDescription
setActions(actions)Set header actions. Action IDs: 'readAll', 'archiveRead', 'archiveAll'.
setListItemActions(actions)Set list item actions. Action IDs: 'read_unread', 'archive_unarchive'.
Popup Menu Control (on <courier-inbox-popup-menu>)
MethodDescription
showPopup()Open the popup programmatically with transition animation.
closePopup()Close the popup programmatically with transition animation.
Static Helper Methods
MethodDescription
CourierInbox.defaultFeeds()Returns the default feeds (Inbox and Archive).
CourierInbox.defaultActions()Returns the default header actions.
CourierInbox.defaultListItemActions()Returns the default list item actions.

Attribute vs Method Usage Many configuration options can be set either via HTML attributes or programmatic methods:
  • HTML attributes: Best for initial, static configuration
  • Programmatic methods: Best for dynamic, runtime configuration
<!-- Using HTML attributes -->
<courier-inbox 
  mode="light"
  light-theme='{"inbox": {"backgroundColor": "#fff"}}'>
</courier-inbox>

<!-- Using programmatic methods -->
<courier-inbox id="inbox"></courier-inbox>
<script type="module">
  const inbox = document.getElementById('inbox');
  inbox.setMode('light');
  inbox.setLightTheme({
    inbox: { backgroundColor: '#fff' }
  });
</script>
Some features are only available via methods (e.g., selectFeed(), refresh(), getFeeds()) and cannot be set via attributes.

Toast Web Components

Toasts are short-lived notifications that notify users and prompt them to take action. The Toast component is connected to the feed of Courier Inbox messages.
Toasts are synced with the Inbox message feed. You can use both components together to provide persistent and temporary notifications.

<courier-toast>
Importing @trycourier/courier-ui-toast registers Courier’s Web Components (<courier-toast>).
<body>
  <courier-toast></courier-toast>

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

    // Generate a JWT for your user on your backend server
    const jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...";

    // Authenticate the user
    Courier.shared.signIn({
      userId: $YOUR_USER_ID,
      jwt: jwt
    });
  </script>
</body>
Sample App: See a complete working example in our Vanilla JS Toast sample app.

HTML Attributes
A note on terminology: toast refers to the entire stack of toasts managed by <courier-toast>, while toast item refers to a single toast displayed for a message.
AttributeTypeDefaultDescription
auto-dismissbooleanfalseWhether toast items should auto-dismiss.
auto-dismiss-timeout-msinteger5000If auto-dismiss is enabled, the timeout in milliseconds before dismissal.
dismiss-button"visible" | "hidden" | "hover" | "auto""auto"Display option for the dismiss button. "auto" makes the button always visible if auto-dismiss is false, and visible on hover if auto-dismiss is true.
light-themejsonundefinedJSON-stringified CourierToastTheme applied in light mode. Merged with defaults.
dark-themejsonundefinedJSON-stringified CourierToastTheme applied in dark mode. Merged with defaults.
mode"light" | "dark" | "system""system"Theme mode for the toast component.
If the auto-dismiss attribute is set, the dismiss button (x) will only be visible on hover and each toast item will automatically be dismissed. A countdown bar is shown to indicate the time remaining before the toast disappears.
Handle Clicks
API MethodDescription
onToastItemClick(handler)Called when a toast item is clicked.
onToastItemActionClick(handler)Called when an action button on a toast item is clicked.
If a message contains actions, toast items will include a button for each. By default, these buttons do not implement any functionality.
index.html
<body>
  <courier-toast id="my-toast"></courier-toast>

  <script type="module">
    import {
      Courier,
      CourierToastDatastore
    } from "@trycourier/courier-ui-toast";

    const toast = document.getElementById("my-toast");

    toast.onToastItemClick(({ message, toastItem }) => {
      window.open(message.actions[0].href);
    });

    toast.onToastItemActionClick(({ message, action }) => {
      window.open(action.href);
      CourierToastDatastore.shared.removeMessage(message);
    });

    Courier.shared.signIn({ userId, jwt });
  </script>
</body>

Styles and Theming
index.html
<body>
  <courier-toast dismiss-button="hidden" id="my-toast"></courier-toast>

  <script type="module">
    import { Courier, CourierToastDatastore } from "@trycourier/courier-ui-toast";
    import ToastIcon from "./toast-icon.svg?raw";

    const toast = document.getElementById("my-toast");

    toast.setLightTheme({
      toast: {
        item: {
          title: {
            color: "#6366f1",
            weight: "bold",
          },
          backgroundColor: "#edeefc",
          border: "1px solid #cdd1ff",
          borderRadius: "15px",
          icon: {
            svg: ToastIcon
          }
        }
      }
    });

    toast.onToastItemClick((props) => {
      window.open(props.message.actions[0].href);
      CourierToastDatastore.shared.removeMessage(props.message);
    });

    Courier.shared.signIn({ userId, jwt });
  </script>
</body>

Custom Elements
MethodDescription
setToastItemContent(factory)Customize the content area only, keeping default stack styling.
setToastItem(factory)Fully replace each toast item for complete control.

Programmatic Control
MethodDescription
enableAutoDismiss()Enable auto-dismiss for toast items.
disableAutoDismiss()Disable auto-dismiss. Items remain visible until manually dismissed.
setAutoDismissTimeoutMs(ms)Set the auto-dismiss timeout in milliseconds.
setDismissButton(option)Set dismiss button visibility: 'visible', 'hidden', 'hover', or 'auto'.
setMode(mode)Set theme mode: 'light', 'dark', or 'system'.
setLightTheme(theme)Set the light theme programmatically.
setDarkTheme(theme)Set the dark theme programmatically.

Toast Datastore CourierToastDatastore is the central repository of Inbox messages from which <courier-toast> listens for messages to display and dismiss. It is a singleton accessed through CourierToastDatastore.shared.
MethodDescription
addMessage(message)Add a message to display as a toast. Messages must include messageId.
removeMessage(message)Remove a message, dismissing any displayed toast for it.
import { CourierToastDatastore } from "@trycourier/courier-ui-toast";

// Add a test message (useful for prototyping)
CourierToastDatastore.shared.addMessage({
  title: "Lorem ipsum dolor sit",
  body: "Lorem ipsum dolor sit amet",
  messageId: "abcd-1234-abcd-1234",
  actions: [{ "content": "Click me!" }]
});

// Remove a message (dismiss its toast)
CourierToastDatastore.shared.removeMessage(message);