Skip to content
design
Components

Tide curve

The predicted height of tide over a period, its high and low waters, and the height now, every height floored.

On this page
Now 0.8 m, rising
m above MSLUTC
  • High water4.3 m
  • Low water0.5 m
  • High water4.3 m
  • Low water0.5 m
A day of tide above mean sea level, with its high and low waters and the height now.
Code
import { TideCurve } from "@bosunkit/components/tide-curve";
import type { ReactElement } from "react";
import { EXTREMES, NOW, SAMPLES } from "./tide-data";

export const description: string =
  "A day of tide at a fixed time: the curve, its high and low waters, and the height now, falling.";

export default function Showcase(): ReactElement {
  return (
    <TideCurve
      samples={SAMPLES}
      extremes={EXTREMES}
      datum="MSL"
      timeZone="UTC"
      timeReference="UTC"
      now={NOW}
      label="Tide at Falmouth"
    />
  );
}

A tide curve draws the predicted height of tide over a period, bosund's GET /tides/curve sampled every 15 minutes, with its high and low waters marked and listed under it and a line at the time now. Every height is floored to a tenth of a meter and a depth as core/i18n floors one (tenths below 10 m, whole meters above), so nothing the crew read says there is more water than predicted. The datum the heights are above and the timeReference of every time are always printed: bosund's prediction is FES2022, whose heights are above mean sea level, not chart datum.

A threshold is a height the crew need, such as the water a bar or a sill needs: it is drawn as a line, the windows when the tide is above it are shaded, and they are listed with their times, each window starting on the minute after the crossing and ending on the minute before. chartedDepthM adds the tide to the charted depth for the depth now. The curve is explored with a slider: a press or the pointer moves it to a time, the arrow keys step 15 minutes and Page Up and Down an hour, and a screen reader hears the time, height and whether the tide is rising. With no prediction it shows an empty state saying so.

relative writes times from now as well, floored as a countdown floors them: each high and low water "in 3 hr 12 min" or "3 hr ago", the slider's time, and with a threshold whether its window is open and when it closes ("Bar: open, closes in 45 min") or next opens.

Examples

A tidal gate

Now 0.8 m, rising
m above MSLUTC

Bar · Above 3.5 m: 01:08–04:52 UTC, 13:33–17:18 UTC

  • High water4.3 m
  • Low water0.5 m
  • High water4.3 m
  • Low water0.5 m
A bar that needs 3.5 m: the windows above it shaded on the curve and listed with their times.
Code
import { TideCurve } from "@bosunkit/components/tide-curve";
import type { ReactElement } from "react";
import { EXTREMES, NOW, SAMPLES } from "./tide-data";

export const description: string =
  "A bar that needs 3.5 m: the windows above it shaded on the curve and listed with their times.";

export default function TidalGate(): ReactElement {
  return (
    <TideCurve
      samples={SAMPLES}
      extremes={EXTREMES}
      datum="MSL"
      timeZone="UTC"
      timeReference="UTC"
      now={NOW}
      threshold={{ heightM: 3.5, label: "Bar" }}
    />
  );
}

Relative times

Now 0.8 m, rising
m above MSLUTC

Bar: opens in 3 hr 13 min

Bar · Above 3.5 m: 01:08–04:52 UTC, 13:33–17:18 UTC

  • High water7 hr 20 min ago4.3 m
  • Low water1 hr 7 min ago0.5 m
  • High waterin 5 hr 5 min4.3 m
  • Low waterin 11 hr 17 min0.5 m
The bar's gate with relative times: when it opens next, and how long until or since each high and low water.
Code
import { TideCurve } from "@bosunkit/components/tide-curve";
import type { ReactElement } from "react";
import { EXTREMES, NOW, SAMPLES } from "./tide-data";

export const description: string =
  "The bar's gate with relative times: when it opens next, and how long until or since each high and low water.";

export default function Relative(): ReactElement {
  return (
    <TideCurve
      samples={SAMPLES}
      extremes={EXTREMES}
      datum="MSL"
      timeZone="UTC"
      timeReference="UTC"
      now={NOW}
      relative
      threshold={{ heightM: 3.5, label: "Bar" }}
    />
  );
}

The depth with the tide

Now 0.8 m, risingDepth 3.6 m
m above MSLUTC
  • High water4.3 m
  • Low water0.5 m
  • High water4.3 m
  • Low water0.5 m
An anchorage charted at 2.8 m: the depth now is the charted depth plus the tide, floored.
Code
import { TideCurve } from "@bosunkit/components/tide-curve";
import type { ReactElement } from "react";
import { EXTREMES, NOW, SAMPLES } from "./tide-data";

export const description: string =
  "An anchorage charted at 2.8 m: the depth now is the charted depth plus the tide, floored.";

export default function Depth(): ReactElement {
  return (
    <TideCurve
      samples={SAMPLES}
      extremes={EXTREMES}
      datum="MSL"
      timeZone="UTC"
      timeReference="UTC"
      now={NOW}
      chartedDepthM={2.8}
    />
  );
}

Night

Now 0.8 m, rising
m above MSLUTC
  • High water4.3 m
  • Low water0.5 m
  • High water4.3 m
  • Low water0.5 m
Sunset to sunrise shaded, for a passage planned to cross the bar in daylight.
Code
import { TideCurve } from "@bosunkit/components/tide-curve";
import type { ReactElement } from "react";
import { EXTREMES, NOW, SAMPLES } from "./tide-data";

export const description: string =
  "Sunset to sunrise shaded, for a passage planned to cross the bar in daylight.";

export default function Night(): ReactElement {
  return (
    <TideCurve
      samples={SAMPLES}
      extremes={EXTREMES}
      datum="MSL"
      timeZone="UTC"
      timeReference="UTC"
      now={NOW}
      nightSpans={[
        { from: Date.UTC(2026, 9, 16, 18, 10), to: Date.UTC(2026, 9, 17, 7, 25) },
        { from: Date.UTC(2026, 9, 17, 18, 8), to: Date.UTC(2026, 9, 18, 7, 27) },
      ]}
    />
  );
}

No prediction

No tide prediction for this position

The tide tables don't cover these waters, so the depth shown is the charted depth only.
Waters no tide table covers: an empty state says so instead of a flat curve.
Code
import { TideCurve } from "@bosunkit/components/tide-curve";
import type { ReactElement } from "react";

export const description: string = "Waters no tide table covers: an empty state says so instead of a flat curve.";

export default function Unavailable(): ReactElement {
  return <TideCurve samples={[]} datum="MSL" timeZone="UTC" timeReference="UTC" now={Date.UTC(2026, 9, 17, 10)} />;
}

Props

PropTypeDefaultDescription
samplesrequiredreadonly TideSample[]–The predicted curve, oldest first; bosund's GET /tides/curve gives one every 15 minutes.
extremesreadonly TideExtreme[] | undefined[]The high and low waters in the period, marked on the curve and listed under it.
datumrequiredstring–The datum the heights are above, printed on the chart ("MSL" for bosund's FES2022 prediction, "LAT", "CD").
timeReferencerequiredstring–The reference every time is printed with, translated by the caller ("UTC", "ship's time").
timeZonestring | undefined–The time zone the times are written in, an IANA name; the browser's unless set. Match it to timeReference.
nownumber | undefined–The current time, for the now line and the height now; the curve keeps a minute clock unless set.
relativeboolean | undefinedfalseWrites times relative to now as well: each high and low water "in 3 hr 12 min" or "3 hr ago", the slider's time, and with a threshold whether its window is open and when it closes or next opens.
thresholdTideThreshold | undefined–A height to be above, drawn as a line, with the windows above it shaded and listed.
chartedDepthMnumber | undefined–The charted depth here, in meters below the datum: the depth now is it plus the tide, floored.
nightSpansreadonly { readonly from: number | string; readonly to: number | string }[] | undefined[]Spans of darkness to shade, such as sunset to sunrise.
labelstring | undefined–The chart's name for a screen reader, translated by the caller ("Tide at Falmouth"); "Tide curve" unless set.
heightnumber | undefined220The plot's height in pixels; 220 unless set.
classNamestring | undefined–Classes added to the chart's own.
testIdstring | undefined–Becomes data-testid on the root.
  • Trend chart: a reading's recent history.
  • Countdown: the time left until a tidal gate opens or closes.