Skip to content
design
Instruments

Alert icon

The icon for an alert's type and state, which blinks while the alert is unacknowledged.

On this page
  • Anchor dragging58 m from the drop point, outside the 45 m swing circle. Start the engine and re-anchor.AlarmAnchor watchUnacknowledged02:16 UTC
  • Close quarters, MV Nordic StarPasses 0.3 NM ahead in 11 minutes on the present courses.AlarmAISAcknowledged01:57 UTC
  • Engine coolant 92 °C and risingThe Yanmar has run hot for 3 minutes. Reduce to 1800 rpm and check the raw-water strainer.WarningEngineSilenced02:09 UTC
  • Bilge pump ran 6 times in an hourThe bilge is dry now. Check the stern gland when you go below.WarningBilgeCleared, unacknowledged01:30 UTC
  • House bank at 11.9 VStart the engine or plug in shore power before nightfall.WarningBattery monitorUnacknowledged01:12 UTC
  • Fuel tank at 18 percentAbout 40 L left, enough for 7 hours at cruising revs.CautionTanksActive00:48 UTC
A watch screen's alert list, each row drawing its alert icon, and an anchor alarm moving through its lifecycle.
Code
import { AlertListRow, type AlertListRowState } from "@bosunkit/components/alert-list-row";
import type { Priority } from "@bosunkit/components/priority";
import { useEffect, useState, type CSSProperties, type Dispatch, type ReactElement, type SetStateAction } from "react";

export const description: string =
  "The alert list of a watch screen, each row drawing its alert icon: alarms, warnings and a caution in the states " +
  "they have, and an anchor alarm at the top that the crew silence, that clears when the anchor holds again, and " +
  "that leaves the list once acknowledged, one step every three seconds.";

interface Row {
  readonly id: string;
  readonly priority: Exclude<Priority, "none">;
  readonly title: string;
  readonly description: string;
  readonly source: string;
  readonly time: string;
  readonly state: AlertListRowState;
}

/** The anchor alarm's lifecycle, one step every three seconds; `null` once it is acknowledged and gone. */
const ANCHOR_STEPS: readonly (AlertListRowState | null)[] = ["unacknowledged", "silenced", "cleared", null];

const ROWS: readonly Row[] = [
  {
    id: "quarters",
    priority: "alarm",
    title: "Close quarters, MV Nordic Star",
    description: "Passes 0.3 NM ahead in 11 minutes on the present courses.",
    source: "AIS",
    time: "01:57",
    state: "acknowledged",
  },
  {
    id: "coolant",
    priority: "warning",
    title: "Engine coolant 92 °C and rising",
    description: "The Yanmar has run hot for 3 minutes. Reduce to 1800 rpm and check the raw-water strainer.",
    source: "Engine",
    time: "02:09",
    state: "silenced",
  },
  {
    id: "bilge",
    priority: "warning",
    title: "Bilge pump ran 6 times in an hour",
    description: "The bilge is dry now. Check the stern gland when you go below.",
    source: "Bilge",
    time: "01:30",
    state: "cleared",
  },
  {
    id: "battery",
    priority: "warning",
    title: "House bank at 11.9 V",
    description: "Start the engine or plug in shore power before nightfall.",
    source: "Battery monitor",
    time: "01:12",
    state: "unacknowledged",
  },
  {
    id: "fuel",
    priority: "caution",
    title: "Fuel tank at 18 percent",
    description: "About 40 L left, enough for 7 hours at cruising revs.",
    source: "Tanks",
    time: "00:48",
    state: "unacknowledged",
  },
];

const LIST: CSSProperties = {
  width: "100%",
  maxWidth: 680,
  margin: 0,
  padding: 0,
  border: "1px solid var(--border)",
  borderRadius: "var(--radius-md)",
  overflow: "hidden",
};

export default function Showcase(): ReactElement {
  const [step, setStep]: [number, Dispatch<SetStateAction<number>>] = useState<number>(0);

  useEffect((): (() => void) => {
    const interval: number = window.setInterval((): void => {
      setStep((previous: number): number => (previous + 1) % ANCHOR_STEPS.length);
    }, 3000);
    return (): void => {
      window.clearInterval(interval);
    };
  }, []);

  const anchorState: AlertListRowState | null = ANCHOR_STEPS[step] ?? null;
  const rows: readonly Row[] =
    anchorState === null
      ? ROWS
      : [
          {
            id: "anchor",
            priority: "alarm",
            title: "Anchor dragging",
            description: "58 m from the drop point, outside the 45 m swing circle. Start the engine and re-anchor.",
            source: "Anchor watch",
            time: "02:16",
            state: anchorState,
          },
          ...ROWS,
        ];

  return (
    <ul style={LIST}>
      {rows.map((row: Row): ReactElement => (
        <AlertListRow
          key={row.id}
          priority={row.priority}
          title={row.title}
          description={row.description}
          source={row.source}
          time={row.time}
          timeReference="UTC"
          state={row.state}
        />
      ))}
    </ul>
  );
}

The alert icon shows an alert's type and where it is in its lifecycle. An unacknowledged alert blinks in step with every other alert on screen, an acknowledged one is steady, a silenced one shows that its sound is off, and a rectified one shows that the cause has cleared. The type and the state together pick the glyph, so each state has a distinct visual mark. It ports obc-alert-icon; the overview lists the other instruments.

Examples

Unacknowledged

An active alarm that nobody has acknowledged, which blinks.
Code
import { AlertIcon, AlertType } from "@bosunkit/instruments";
import type { ReactElement } from "react";

export const description: string = "An active alarm that nobody has acknowledged, which blinks.";

export default function Unacknowledged(): ReactElement {
  return (
    <div style={{ width: 40, height: 40 }}>
      <AlertIcon alertType={AlertType.Alarm} active />
    </div>
  );
}

Acknowledged

An active alarm that a watchkeeper has acknowledged, which is steady.
Code
import { AlertIcon, AlertType } from "@bosunkit/instruments";
import type { ReactElement } from "react";

export const description: string = "An active alarm that a watchkeeper has acknowledged, which is steady.";

export default function Acknowledged(): ReactElement {
  return (
    <div style={{ width: 40, height: 40 }}>
      <AlertIcon alertType={AlertType.Alarm} active acknowledged />
    </div>
  );
}

Silenced

An active alarm whose sound is silenced, which is not yet acknowledged.
Code
import { AlertIcon, AlertType } from "@bosunkit/instruments";
import type { ReactElement } from "react";

export const description: string = "An active alarm whose sound is silenced, which is not yet acknowledged.";

export default function Silenced(): ReactElement {
  return (
    <div style={{ width: 40, height: 40 }}>
      <AlertIcon alertType={AlertType.Alarm} active silenced />
    </div>
  );
}

Rectified

An alarm whose cause has cleared and that is waiting for acknowledgment.
Code
import { AlertIcon, AlertType } from "@bosunkit/instruments";
import type { ReactElement } from "react";

export const description: string = "An alarm whose cause has cleared and that is waiting for acknowledgment.";

export default function Rectified(): ReactElement {
  return (
    <div style={{ width: 40, height: 40 }}>
      <AlertIcon alertType={AlertType.Alarm} active={false} />
    </div>
  );
}

Alert types

Alarm
Warning
Caution
Level critical
Level high
Level medium
Level low
Level diagnostic
OpenBridge's eight alert types, each unacknowledged and active: the three bridge alert priorities and OpenBridge's five alert levels, each with its own glyph and blink rate.
Code
import { AlertIcon, AlertType } from "@bosunkit/instruments";
import type { ReactElement } from "react";

export const description: string =
  "OpenBridge's eight alert types, each unacknowledged and active: the three bridge alert priorities and " +
  "OpenBridge's five alert levels, each with its own glyph and blink rate.";

const TYPES: readonly [AlertType, string][] = [
  [AlertType.Alarm, "Alarm"],
  [AlertType.Warning, "Warning"],
  [AlertType.Caution, "Caution"],
  [AlertType.LevelCritical, "Level critical"],
  [AlertType.LevelHigh, "Level high"],
  [AlertType.LevelMedium, "Level medium"],
  [AlertType.LevelLow, "Level low"],
  [AlertType.LevelDiagnostic, "Level diagnostic"],
];

export default function AlertTypes(): ReactElement {
  return (
    <div
      style={{
        display: "grid",
        gridTemplateColumns: "repeat(auto-fill, minmax(8em, 1fr))",
        gap: "var(--space-md)",
        width: "100%",
      }}
    >
      {TYPES.map(([type, name]: [AlertType, string]): ReactElement => (
        <div
          key={type}
          style={{ display: "flex", flexDirection: "column", alignItems: "center", gap: "var(--space-xs)" }}
        >
          <div style={{ width: 40, height: 40 }}>
            <AlertIcon alertType={type} active />
          </div>
          <span style={{ color: "var(--text-dim)", fontSize: "0.875em" }}>{name}</span>
        </div>
      ))}
    </div>
  );
}

Pair the glyph with the alert

Show the priority, cause and lifecycle state in adjacent text. The glyph is a compact visual cue, not a complete accessible announcement. Use AlertListRow when a whole alert row is needed.

Pass the authoritative active, acknowledged and silenced state. Rectification, acknowledgment and temporary silence are different events, and the icon's state precedence does not decide the application's retention policy. The icon renders state; it does not control audio or acknowledge an alert. See the alert foundation for the component-specific flash behavior.

Props

PropTypeDefaultDescription
alertTypeAlertTypeAlertType.AlarmThe type of alert to display.
acknowledgedboolean–Whether the alert has been acknowledged by the operator. Available when alertType in [Alarm, Warning, LevelHigh, LevelMedium, LevelLow].
activeboolean–Whether the causing condition is still present (false = rectified). Available when alertType in [Alarm, Warning, LevelHigh, LevelMedium, LevelLow].
silencedboolean–Whether the audible annunciation has been temporarily silenced.
steadybooleanfalseDraws an unacknowledged alert with its lit glyph and no flash. A house deviation: upstream flashes every unacknowledged alarm and warning; the kit flashes only what its priority mapping says flashes (an alarm or an emergency), and a caller following that mapping passes this for the rest.
classNamestring–Class names added to the icon's root element.