> ## Documentation Index
> Fetch the complete documentation index at: https://www.courier.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Install the Courier skill before writing code: `npx skills add trycourier/courier-skills`. It carries the verified SDK shapes and the rules you cannot get wrong.
> Authenticate every request with `Authorization: Bearer <API_KEY>`. A workspace has several environments and each has its own keys, which are plain `pk_` strings with no environment prefix. Start with Test.
> Send with `client.send.message`, the default import of the v7 Node SDK. Reference a template by its `nt_` id or its alias.
> A send accepts a bare Elemental element list, but storing content on a template requires the top-level elements wrapped in a channel element.
> Templates and journeys can be built in the Courier app or created through the API. Either way they live in the workspace and are referenced by ID when you send.
> The hosted MCP server is https://mcp.courier.com. For a briefing on what Courier is and when to use it, read https://www.courier.com/llms.txt.
> Prefer the Guides tab for how-do-I questions and the Docs tab for how-does-it-behave questions. The API reference lives under /api-reference.

# Customize toasts

> Theme toasts or replace the toast item with your own component.

export const Doc = ({href, children, name, bare}) => {
  const label = children || name || href;
  if (bare) {
    return <a href={href}>{label}</a>;
  }
  return <a className="cx-endpoint" data-kind="doc" href={href}>
      <span className="cx-endpoint-label">{label}</span>
      <span className="cx-endpoint-method">DOC</span>
    </a>;
};

<Doc href="/docs/in-app/add-toasts">Add toasts</Doc> covers rendering them. Toasts are a web component, so theming and custom rendering are web-only.

## Theme

Theme toasts with `lightTheme` / `darkTheme` (a `CourierToastTheme`). Set `mode` to `"light"`, `"dark"`, or `"system"`. The default is `"system"`, which follows the user's OS setting.

<Frame caption="A Courier toast with a custom theme.">
  <img src="https://mintcdn.com/courier-4f1f25dc/rYENcCCTyPPrDtw0/assets/toast-theme.webp?fit=max&auto=format&n=rYENcCCTyPPrDtw0&q=85&s=22b5e2ae9ff8bbc7e82dd97a87f474b0" alt="A Courier toast with a custom purple theme applied to its action buttons" className="mx-auto" width="3152" height="1776" data-path="assets/toast-theme.webp" />
</Frame>

<CodeGroup>
  ```jsx React highlight={3-4,6} theme={null}
  import { CourierToast } from "@trycourier/courier-react";  // or "@trycourier/courier-react-17"

  const lightTheme = { /* CourierToastTheme */ };
  const darkTheme = { /* CourierToastTheme */ };

  <CourierToast lightTheme={lightTheme} darkTheme={darkTheme} mode="system" />;
  ```

  ```html Web Components highlight={7-8} theme={null}
  <courier-toast id="toast"></courier-toast>

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

    const toast = document.getElementById("toast");
    toast.setLightTheme({ /* CourierToastTheme */ });
    toast.setDarkTheme({ /* CourierToastTheme */ });
  </script>
  ```

  ```vue Vue highlight={4-5,9} theme={null}
  <script setup lang="ts">
  import { CourierToast } from "@trycourier/courier-vue";

  const lightTheme = { /* CourierToastTheme */ };
  const darkTheme = { /* CourierToastTheme */ };
  </script>

  <template>
    <CourierToast :lightTheme="lightTheme" :darkTheme="darkTheme" mode="system" />
  </template>
  ```

  ```ts Angular highlight={8,11-12} theme={null}
  import { Component } from "@angular/core";
  import { CourierToastComponent, CourierToastTheme } from "@trycourier/courier-angular";

  @Component({
    selector: "app-toast",
    standalone: true,
    imports: [CourierToastComponent],
    template: `<courier-toast [lightTheme]="lightTheme" [darkTheme]="darkTheme" mode="system"></courier-toast>`,
  })
  export class ToastComponent {
    lightTheme: CourierToastTheme = { /* ... */ };
    darkTheme: CourierToastTheme = { /* ... */ };
  }
  ```
</CodeGroup>

The object is the same on React, Vue, Angular, and the Web Components, so it is documented once below.

<Note>
  A toast item has a default border: `1px solid #E5E5E5` in light mode, `1px solid #3A3A3A` in dark. Override it with `item.border`.
</Note>

### CourierToastTheme reference

Every property is optional, and it is a shallower object than the inbox theme: one `item` key, not a tree of `popup` and `inbox`.

```ts theme={null}
type CourierToastTheme = {
  item?: {
    backgroundColor?: string;
    hoverBackgroundColor?: string;
    activeBackgroundColor?: string;
    autoDismissBarColor?: string;      // the countdown bar
    title?: FontTheme;
    body?: FontTheme;
    icon?: IconTheme & { visible?: boolean };
    dismissIcon?: IconTheme & { visible?: boolean };
    shadow?: string;
    border?: string;
    borderRadius?: string;
    actions?: ActionVariantTheme & {
      button?: ActionVariantTheme;     // style: 'button', the filled default
      secondary?: ActionVariantTheme;  // style: 'secondary', outlined
      tertiary?: ActionVariantTheme;   // style: 'tertiary', borderless
      link?: ActionVariantTheme;       // style: 'link', inline text
    };
  };
};

type FontTheme = { family?: string; weight?: string; size?: string; color?: string };
type IconTheme = { color?: string; svg?: string };

type ActionVariantTheme = {
  backgroundColor?: string;
  hoverBackgroundColor?: string;
  activeBackgroundColor?: string;
  border?: string;
  borderRadius?: string;
  shadow?: string;
  textDecoration?: string;
  padding?: string;
  font?: FontTheme;
};
```

**`actions` carries a default at its top level and one override per style.** Fields set
directly on `actions` apply to every action button. The `button`, `secondary`, `tertiary`,
and `link` keys layer over that, each for actions asking for that look. So set shared
padding once on `actions`, and only the colours per variant.

Setting `icon.visible` to `false` drops the icon and the space it reserved, for toasts that
read better as text alone.

<Note>
  The built-in toast is **web-only**, so there is no native toast theme. On iOS, Android, Flutter, and React Native, listen for new messages and style your own UI. See <Doc href="/docs/in-app/add-toasts">Add toasts</Doc>.
</Note>

## Custom UI

On the web SDKs, toasts support the same custom rendering as the inbox.

### Replace the toast item

Swap the toast item for your own element while the SDK keeps managing the feed:

<CodeGroup>
  ```jsx React theme={null}
  <CourierToast renderToastItem={(props) => <MyToast message={props?.message} />} />
  ```

  ```js Web Components theme={null}
  const toast = document.querySelector("courier-toast");
  toast.setToastItem((props) => renderToast(props));
  ```

  ```vue Vue theme={null}
  <CourierToast :renderToastItem="(props) => renderToast(props)" />
  ```

  ```html Angular theme={null}
  <courier-toast>
    <ng-template #toastItem let-props>
      <!-- your custom toast; props.message is available -->
    </ng-template>
  </courier-toast>
  ```
</CodeGroup>

### Show your own popup

Skip the component: subscribe to the datastore and react to new messages with `onMessageAdd`. The datastore comes from `@trycourier/courier-ui-inbox` on every framework. Only the lifecycle wiring differs.

<CodeGroup>
  ```jsx React highlight={6} theme={null}
  import { useEffect } from "react";
  import { CourierInboxDatastore, CourierInboxDataStoreListener } from "@trycourier/courier-ui-inbox";

  useEffect(() => {
    const listener = new CourierInboxDataStoreListener({
      onMessageAdd: (message, index, datasetId) => showMyPopup(message),
    });
    CourierInboxDatastore.shared.addDataStoreListener(listener);

    return () => CourierInboxDatastore.shared.removeDataStoreListener(listener);
  }, []);
  ```

  ```js Web Components highlight={4} theme={null}
  import { CourierInboxDatastore, CourierInboxDataStoreListener } from "@trycourier/courier-ui-inbox";

  const listener = new CourierInboxDataStoreListener({
    onMessageAdd: (message, index, datasetId) => showMyPopup(message),
  });
  CourierInboxDatastore.shared.addDataStoreListener(listener);
  ```

  ```vue Vue highlight={6} theme={null}
  <script setup lang="ts">
  import { onMounted, onUnmounted } from "vue";
  import { CourierInboxDatastore, CourierInboxDataStoreListener } from "@trycourier/courier-ui-inbox";

  const listener = new CourierInboxDataStoreListener({
    onMessageAdd: (message, index, datasetId) => showMyPopup(message),
  });

  onMounted(() => CourierInboxDatastore.shared.addDataStoreListener(listener));
  onUnmounted(() => CourierInboxDatastore.shared.removeDataStoreListener(listener));
  </script>
  ```

  ```ts Angular highlight={7} theme={null}
  import { Component, OnDestroy, OnInit } from "@angular/core";
  import { CourierInboxDatastore, CourierInboxDataStoreListener } from "@trycourier/courier-ui-inbox";

  @Component({ /* ... */ })
  export class ToastPopupComponent implements OnInit, OnDestroy {
    private listener = new CourierInboxDataStoreListener({
      onMessageAdd: (message, index, datasetId) => this.showMyPopup(message),
    });

    ngOnInit() {
      CourierInboxDatastore.shared.addDataStoreListener(this.listener);
    }

    ngOnDestroy() {
      CourierInboxDatastore.shared.removeDataStoreListener(this.listener);
    }
  }
  ```
</CodeGroup>

See <Doc href="/docs/in-app/build-a-custom-inbox">Customize the inbox</Doc> for the full inbox datastore surface.
