Skip to main content
Toast UI Preview
This is the latest version of the Courier Toast 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 Toast Web Components and exposes a similar API.

Installation

Available on GitHub and npm.
npm install @trycourier/courier-ui-toast
The Courier SDKs work with any JavaScript build system and do not require any additional build configuration.
Using React? Check out the Courier Toast React 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.
If you’ve already setup authentication for Courier Inbox, you can skip this step. Courier Toasts and Inbox share an authentication mechanism and connection to the Courier backend.

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.
CLI
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"
  }'

Toast Web Components

Toasts are short-lived notifications that notify users and prompt them to take action. Courier’s Toast component is connected to the feed of Courier Inbox messages.

<courier-toast>

Courier Toast component

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>

HTML Attributes

<courier-toast> exposes various attributes and methods to customize its appearance and functionality.
A note on terminology: In method names and documentation, toast is used to refer to the entire stack of toasts maintained and presented 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 instance applied if mode is light. The theme provided here is merged with the SDK’s default theme values.
dark-themejsonundefinedJSON-stringified CourierToastTheme instance applied if mode is dark. The theme provided here is merged with the SDK’s default theme values.
mode"light" | "dark" | "system""system"Theme mode for the toast component.

Auto-dismiss

Toast component with auto-dismiss enabled.

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. The time the toast is displayed can be configured with the attribute auto-dismiss-timeout-ms. The countdown bar color is theme-able. See Styles and Theming below.

Handle Clicks

Toast Items

API Method
onToastItemClick(handler?: (props: CourierToastItemClickEvent) => void): void
Set the handler invoked when a toast item is clicked. The handler is called with CourierToastItemClickEvent, included below. The click handler will be added to either the default CourierToastItem or a custom toast item implementation if one is provided via setToastItem. As an example, you might attach a custom click handler to open a URL from the message.
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);
    });

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

Action Buttons

API Method
onToastItemActionClick(handler?: (props: CourierToastItemActionClickEvent) => void): void

Courier Toast with action buttons

If a message contains actions, toast items will include a button for each. By default, these buttons do not implement any functionality. Use onToastItemActionClick to set the handler invoked when an action button is clicked. The handler is called with CourierToastItemActionClickEvent, included below. As an example, you might attach a click handler to open the URL in the action that was clicked and dismiss the toast.
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.onToastItemActionClick(({ message, action }) => {
      window.open(action.href);
      CourierToastDatastore.shared.removeMessage(message);
    });

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

Styles and Theming

Combined with the attributes listed above, the fastest way to style Courier toasts is with a custom theme.

Light and Dark Themes

Courier toasts with a custom light theme

The example below themes various style elements, sets a custom SVG as the icon, and hides the dismiss button. Building on the previous click handling example, it listens to the click event to open the action URL attached to the message and dismiss the message.
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);
    });

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

CourierToastTheme

An instance of CourierToastTheme can be set as the light and dark themes respectively.

Custom Elements

Custom Content

API Method
setToastItemContent(factory?: (props: CourierToastItemFactoryProps) => HTMLElement): void
Customize only the content area of each toast item while reusing the default stack structure and styling by passing a factory function to setToastItemContent. By default the dismiss button is still rendered if custom content is set. The example below disables the default dismiss button by setting the dismiss-button="hidden" attribute, builds up content with a custom dismiss button, and dismisses the toast with a call to CourierToastDatastore.

Toast with custom item content

index.html
<html>
<head>
  <link href="./styles.css" rel="stylesheet">
</head>
<body>
  <courier-toast id="my-toast" dismiss-button="hidden"></courier-toast>

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

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

    toast.setToastItemContent(({ message }) => {
      const content = document.createElement("div");
      content.className = "toast-content";

      const icon = document.createElement("img");
      icon.className = "toast-icon";
      icon.src = "./toast-icon.svg";
      icon.width = 24;
      icon.height = 24;

      const textContainer = document.createElement("div");
      textContainer.className = "toast-text";

      const title = document.createElement("strong");
      title.className = "toast-title";
      title.textContent = message.title;

      const body = document.createElement("p");
      body.className = "toast-body";
      body.textContent = message.body;

      textContainer.appendChild(title);
      textContainer.appendChild(body);

      const dismissButton = document.createElement("button");
      dismissButton.className = "toast-dismiss";
      dismissButton.textContent = "×";
      dismissButton.addEventListener("click", () => {
        CourierToastDatastore.shared.removeMessage(message);
      });

      content.appendChild(icon);
      content.appendChild(textContainer);
      content.appendChild(dismissButton);

      return content;
    });

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

Fully Custom Items

API Method
setToastItem(factory?: (props: CourierToastItemFactoryProps) => HTMLElement): void
Customize each toast item’s appearance and behavior by passing a factory function to setToastItem, which will be called to create a toast item. This is useful for complete control over the toast and its stack, since the custom item will not have any default styling attached. auto-dismiss and auto-dismiss-timeout-ms are valid attributes when using both the default and custom toast items. If auto-dismiss is true, the custom item will be automatically removed after auto-dismiss-timeout-ms milliseconds. You may want to use those parameters passed to the factory function to create the item.

Toast with a fully custom item

index.html
<html>
<head>
  <link href="./styles.css" rel="stylesheet">
</head>
<body>
  <courier-toast id="my-toast"></courier-toast>

  <script type="module">
    const toast = document.getElementById("my-toast");

    toast.setToastItem((props) => {
      const { message, dismiss } = props;

      const container = document.createElement("div");
      container.className = "toast-content";

      const messageDiv = document.createElement("div");
      messageDiv.className = "toast-message";

      const title = document.createElement("strong");
      title.className = "toast-title";
      title.textContent = message.title;

      const body = document.createElement("p");
      body.className = "toast-body";
      body.textContent = message.body;

      messageDiv.appendChild(title);
      messageDiv.appendChild(body);

      const actionsDiv = document.createElement("div");
      actionsDiv.className = "toast-actions";

      if (message.actions) {
        message.actions.forEach(action => {
          const button = document.createElement("button");
          button.className = "toast-action-button";
          button.textContent = action.content;
          button.onclick = () => {
            if (action.href) {
              window.open(action.href);
            }
          };
          actionsDiv.appendChild(button);
        });
      }

      container.appendChild(messageDiv);
      container.appendChild(actionsDiv);

      return container;
    });

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

Toast Datastore

CourierToastDatastore is the central repository of Inbox messages from which the <courier-toast> listens to messages to display and dismiss. As seen in a few examples above, it can be useful to manually manipulate the datastore to dismiss messages in response to user interactions, like clicking an action button. CourierToastDatastore is a singleton and should be used through its shared instance.

Add a message

API Method
CourierToastDatastore.shared.addMessage(message: InboxMessage): void
Add a message, which will display it as a toast item. Since toasts are ephemeral, calling addMessage can be useful in development to quickly prototype how toasts appear in your app. For example, add a message with an action. Messages must include messageId.
app.ts
import { CourierToastDatastore } from "@trycourier/courier-ui-toast";

CourierToastDatastore.shared.addMessage({
  title: "Lorem ipsum dolor sit",
  body: "Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet",
  messageId: "abcd-1234-abcd-1234",
  actions: [
    {
      "content": "Click me!"
    }
  ]
});

Remove a message

API Method
CourierToastDatastore.shared.removeMessage(message: InboxMessage): void
Remove a message, which will dismiss any toasts currently displayed for this message. removeMessage can be useful to implement your own toast dismissal logic, as in the example below.
app.ts
import {
  CourierToastDatastore,
  CourierToast
}
from "@trycourier/courier-ui-toast";

const toast = document.querySelector("courier-toast") as CourierToast;

toast.onToastItemClick(({ message }) => {
  CourierToastDatastore.shared.removeMessage(message);
});