Skip to content
design
Components

Alert list

The active alerts as a named list of rows, grouped by priority and newest first, with an empty state.

On this page
  • Anchor dragging41 m from where the anchor was dropped, outside the 35 m swing radius.AlarmAnchor watchUnacknowledged02:16 UTC
  • Bilge pump ran 4 times in an hourWarningBilgeAcknowledged02:02 UTC
  • House bank at 11.9 VStart the engine or the generator to charge it.WarningBattery monitorSilenced01:40 UTC
  • Wind sensor reading steady for 20 minCautionMastheadActive01:58 UTC
The active alerts at anchor at night, listed by priority and then newest first, with the anchor alarm waiting to be acknowledged.
Code
import { AlertList, type AlertListItem } from "@bosunkit/components/alert-list";
import { useState, type Dispatch, type ReactElement, type SetStateAction } from "react";

export const description: string =
  "The active alerts at anchor in Cala Portals at 02:20 UTC, given in the order they were raised and listed by " +
  "priority, then newest first: acknowledge the anchor alarm and it reads acknowledged once the board confirms it.";

/** How long the board takes to confirm an acknowledgement. */
const CONFIRM_AFTER_MS: number = 1200;

export default function Showcase(): ReactElement {
  const [acknowledged, setAcknowledged]: [boolean, Dispatch<SetStateAction<boolean>>] = useState<boolean>(false);
  const alerts: readonly AlertListItem[] = [
    {
      id: "battery",
      priority: "warning",
      title: "House bank at 11.9 V",
      description: "Start the engine or the generator to charge it.",
      source: "Battery monitor",
      time: "01:40",
      timeReference: "UTC",
      state: "silenced",
      raisedAt: Date.UTC(2026, 9, 11, 1, 40),
    },
    {
      id: "wind",
      priority: "caution",
      title: "Wind sensor reading steady for 20 min",
      source: "Masthead",
      time: "01:58",
      timeReference: "UTC",
      state: "unacknowledged",
      raisedAt: Date.UTC(2026, 9, 11, 1, 58),
    },
    {
      id: "drag",
      priority: "alarm",
      title: "Anchor dragging",
      description: "41 m from where the anchor was dropped, outside the 35 m swing radius.",
      source: "Anchor watch",
      time: "02:16",
      timeReference: "UTC",
      state: acknowledged ? "acknowledged" : "unacknowledged",
      raisedAt: Date.UTC(2026, 9, 11, 2, 16),
      acknowledgeAction: async (): Promise<void> => {
        await new Promise<void>((resolve: () => void): void => {
          setTimeout(resolve, CONFIRM_AFTER_MS);
        });
        setAcknowledged(true);
      },
    },
    {
      id: "bilge",
      priority: "warning",
      title: "Bilge pump ran 4 times in an hour",
      source: "Bilge",
      time: "02:02",
      timeReference: "UTC",
      state: "acknowledged",
      raisedAt: Date.UTC(2026, 9, 11, 2, 2),
    },
  ];
  return (
    <div style={{ width: "100%", maxWidth: "40em" }}>
      <AlertList label="Active alerts" alerts={alerts} />
    </div>
  );
}

An alert list holds alert list rows in a list named by its label. It takes the alerts as data and orders them as MSC.302 §9.16 asks: grouped by priority (emergency alarm, alarm, warning, caution) and, within a priority, by time of occurrence, newest first. The caller passes the alerts in any order, and orderAlerts gives the same order to a caller that needs it elsewhere. An empty list says there is nothing, and a list longer than its room says how many more alerts there are (§9.11–9.12).

Tab passes through each row's controls in the list's order. The up and down arrows move between the rows, and Home and End go to the first and the last. A new alert takes its place in the list at once; the list does not animate.

01Most urgent firstAn alarm sits above every warning, whenever each was raised, so the crew's first look lands on what needs them now.
02Never silent about what is missingAn empty list says so in words, and a list cut short says how many alerts are not shown.
03One alert at a timeEach row acknowledges its own alert; the list has no control that acknowledges them all.

Examples

Empty

    No active alerts

      Nothing has cleared in the last 24 hr.

      An empty list says so: in the kit's words for the active alerts, and in the caller's for a cleared list.
      Code
      import { AlertList } from "@bosunkit/components/alert-list";
      import type { ReactElement } from "react";
      
      export const description: string =
        "An empty list says so: in the kit's words for the active alerts, and in the caller's for a cleared list.";
      
      export default function Empty(): ReactElement {
        return (
          <div style={{ display: "grid", gap: "var(--space-md)", width: "100%", maxWidth: "32em" }}>
            <AlertList label="Active alerts" alerts={[]} />
            <AlertList label="Cleared alerts" alerts={[]} emptyText="Nothing has cleared in the last 24 hr." />
          </div>
        );
      }
      

      Longer than its room

      limit lists the most urgent alerts and counts the rest under them.

      • Anchor draggingAlarmAcknowledged02:16 UTC
      • True wind above 25 knWarningAcknowledged02:05 UTC
      • House bank at 11.9 VWarningSilenced01:40 UTC

      2 more alerts

      Five alerts with room for three: the most urgent three are listed and the list says 2 more alerts.
      Code
      import { AlertList, type AlertListItem } from "@bosunkit/components/alert-list";
      import type { ReactElement } from "react";
      
      export const description: string =
        "Five alerts with room for three: the most urgent three are listed and the list says 2 more alerts.";
      
      const ALERTS: readonly AlertListItem[] = [
        {
          id: "a",
          priority: "caution",
          title: "Fridge at 9 °C",
          time: "00:12",
          timeReference: "UTC",
          state: "unacknowledged",
          raisedAt: 1,
        },
        {
          id: "b",
          priority: "warning",
          title: "House bank at 11.9 V",
          time: "01:40",
          timeReference: "UTC",
          state: "silenced",
          raisedAt: 2,
        },
        {
          id: "c",
          priority: "caution",
          title: "AIS target count above 40",
          time: "01:51",
          timeReference: "UTC",
          state: "unacknowledged",
          raisedAt: 3,
        },
        {
          id: "d",
          priority: "alarm",
          title: "Anchor dragging",
          time: "02:16",
          timeReference: "UTC",
          state: "acknowledged",
          raisedAt: 4,
        },
        {
          id: "e",
          priority: "warning",
          title: "True wind above 25 kn",
          time: "02:05",
          timeReference: "UTC",
          state: "acknowledged",
          raisedAt: 5,
        },
      ];
      
      export default function Limit(): ReactElement {
        return (
          <div style={{ width: "100%", maxWidth: "32em" }}>
            <AlertList label="Active alerts" alerts={ALERTS} limit={3} />
          </div>
        );
      }
      

      Props

      PropTypeDefaultDescription
      labelrequiredstring–What the list holds ("Active alerts"), as the caller displays it; it names the list.
      alertsrequiredreadonly AlertListItem[]–The alerts, in any order: the list groups them by priority and orders each group by time, newest first.
      emptyTextstring | undefined–What the list says when it holds no alert; "No active alerts" in the crew's language by default.
      limitnumber | undefined–The most rows shown; the list then says how many more there are. All of them by default.
      classNamestring | undefined–Classes added to the list's own.
      testIdstring | undefined–data-testid on the list's root; each row is ${testId}--${id}, and its parts --empty and --more.
      refRef<HTMLDivElement> | undefined–The list's root element.
      Do
      • Anchor draggingAlarmAcknowledged02:16 UTC
      • House bank at 11.9 VWarningSilenced01:40 UTC
      Give the list every alert and let it order them: the alarm comes first though it was raised last.
      Don't
      • House bank at 11.9 VWarningSilenced01:40 UTC
      • Anchor draggingAlarmAcknowledged02:16 UTC
      Don't build the list from rows in the order they arrived. A warning raised first pushes the alarm down.