Weather bar
The weather now on one line, with the forecast by day, the sea state and the model run a tap below it.
On this page
Code
import { WeatherBar } from "@bosunkit/components/weather-bar";
import type { ReactElement } from "react";
export const description: string =
"Day two of a Biscay crossing from A Coruña to Falmouth, opened: five days with their sky, cloud cover, wind and " +
"gusts, waves, rain and visibility, each with its trend through the day; Wednesday's thunderstorm gale over the " +
"reef and heavy-sea limits; a rough sea on an Atlantic swell; a falling barometer; a thunderstorm risk and the " +
"ECMWF run behind it.";
export default function Showcase(): ReactElement {
return (
<WeatherBar
current={{
description: "Moderate rain showers",
wind: "22 kn, gusts 31 kn",
conditions: "building",
weatherCode: 81,
cloudCoverPct: 75,
windFromDeg: 235,
}}
forecasts={[
{ period: "+6H", wind: "25–30 kn", conditions: "" },
{ period: "+12H", wind: "28–36 kn", conditions: "veering" },
]}
temperature="16 °C"
pressure="1004 hPa"
seaStateText="2.9 m"
days={[
{
day: "Mon 13",
weatherCode: 2,
cloudCoverPct: 45,
windMinKn: 14,
windMaxKn: 19,
windFromDeg: 250,
gustMaxKn: 26,
waveHeightM: 2.1,
precipitationMm: 0.4,
visibilityMinM: 24000,
hours: {
windKn: [14, 15, 16, 18, 19, 18, 16, 15],
gustKn: [19, 21, 23, 25, 26, 25, 22, 20],
waveHeightM: [1.9, 2.0, 2.0, 2.1, 2.1, 2.1, 2.0, 2.0],
precipitationMm: [0, 0, 0, 0.1, 0.2, 0.1, 0, 0],
cloudCoverPct: [30, 40, 45, 55, 50, 45, 40, 35],
},
},
{
day: "Tue 14",
weatherCode: 81,
cloudCoverPct: 70,
windMinKn: 18,
windMaxKn: 26,
windFromDeg: 235,
gustMaxKn: 36,
waveHeightM: 2.9,
precipitationMm: 6.2,
visibilityMinM: 9000,
hours: {
windKn: [18, 19, 21, 23, 25, 26, 24, 22],
gustKn: [25, 27, 30, 33, 35, 36, 33, 31],
waveHeightM: [2.2, 2.4, 2.5, 2.7, 2.8, 2.9, 2.9, 2.8],
precipitationMm: [0, 0.4, 1.2, 0.8, 1.9, 1.1, 0.6, 0.2],
cloudCoverPct: [55, 65, 75, 80, 70, 75, 70, 65],
},
},
{
day: "Wed 15",
weatherCode: 95,
cloudCoverPct: 95,
windMinKn: 28,
windMaxKn: 38,
windFromDeg: 225,
gustMaxKn: 49,
waveHeightM: 4.6,
precipitationMm: 18.4,
visibilityMinM: 2600,
hours: {
windKn: [28, 30, 33, 36, 38, 37, 34, 31],
gustKn: [37, 40, 44, 48, 49, 47, 43, 39],
waveHeightM: [3.2, 3.5, 3.9, 4.3, 4.6, 4.5, 4.2, 3.9],
precipitationMm: [0.8, 1.6, 3.2, 4.1, 3.7, 2.6, 1.6, 0.8],
cloudCoverPct: [85, 90, 100, 100, 100, 95, 95, 90],
},
},
{
day: "Thu 16",
weatherCode: 80,
cloudCoverPct: 60,
windMinKn: 16,
windMaxKn: 24,
windFromDeg: 290,
gustMaxKn: 34,
waveHeightM: 3.8,
precipitationMm: 3.1,
visibilityMinM: 12000,
hours: {
windKn: [24, 23, 21, 19, 18, 17, 16, 16],
gustKn: [34, 32, 30, 27, 25, 24, 22, 22],
waveHeightM: [3.8, 3.7, 3.6, 3.5, 3.4, 3.3, 3.2, 3.1],
precipitationMm: [0.9, 0.7, 0.6, 0.4, 0.3, 0.1, 0.1, 0],
cloudCoverPct: [80, 75, 70, 60, 55, 50, 45, 45],
},
},
{
day: "Fri 17",
weatherCode: 0,
cloudCoverPct: 10,
windMinKn: 9,
windMaxKn: 15,
windFromDeg: 315,
gustMaxKn: 21,
waveHeightM: 2.6,
precipitationMm: 0,
visibilityMinM: 30000,
hours: {
windKn: [15, 14, 13, 12, 11, 10, 9, 9],
gustKn: [21, 20, 18, 17, 15, 14, 13, 12],
waveHeightM: [2.6, 2.4, 2.3, 2.1, 2.0, 1.9, 1.9, 1.8],
precipitationMm: [0, 0, 0, 0, 0, 0, 0, 0],
cloudCoverPct: [20, 15, 10, 10, 5, 5, 10, 10],
},
},
]}
sea={{
waveHeightM: 2.9,
wavePeriodS: 8,
waveFromDeg: 240,
swellHeightM: 2.2,
swellPeriodS: 12,
swellFromDeg: 285,
douglas: 5,
}}
pressureTrendHpa3h={-3.4}
pressureHourlyHpa={[1009.6, 1009.1, 1008.6, 1008.1, 1007.6, 1006.4, 1005.3, 1004.2]}
visibilityM={7400}
convection={{ capeJPerKg: 1350, liftedIndex: -3.2, risk: "possible" }}
model={{
name: "ECMWF IFS",
run: "00:00 UTC",
ageHours: 7,
confidence: 0.62,
windSpreadKn: { low: 19, high: 27 },
}}
limits={{ reefWindKn: 20, heavySeaM: 3, pressureDropHpa3h: 3, fogVisibilityM: 1000 }}
defaultOpen
/>
);
}
A weather bar puts the weather now on one line: the sky's glyph, the wind with an arrow pointing downwind, the temperature, pressure and sea state, and the wind for the next periods. Given a forecast by day, a sea state, the weather beyond wind and sea, or the model run, the line gains a control that opens the detail under it, closed until the crew opens it.
The detail starts with a row per day across the bar's whole width. The sky cell draws a filled glyph (sun, clouds,
rain, snow, fog or a bolt) from the day's WMO weather code and writes the code's name, with a quieter line under it:
the cloud cover in percent, the day's lowest visibility and the code itself. A source without a code gets its glyph
and name from the cloud cover in oktas: 0–2 clear, 3–4 partly cloudy, 5–7 mostly cloudy, 8 overcast. Wind and gusts
share a cell ("18–26 kn, gusts 36"), then come the waves and the rain. Each measure's cell holds its value, a limit
mark and a small trend of the day hour by hour, every day on one scale: wind with its gusts and the reef limit, waves
with the heavy-sea limit, rain as bars (none on a dry day), cloud cover as an area. On a wide bar the three share one
line with the trend at the cell's right edge; on a narrow one the trend and the mark go under the value. Either way
each column's trends start at one edge, so the days compare at a glance. On a phone held upright each day is a block:
the day and its sky take a line each, and the wind, waves and rain sit side by side under them, each named above its
value, so nothing scrolls sideways. After the days come the sea state with its swell and Douglas scale; the pressure
trend with the barometer by the hour (the record up to now, then pressureForecastHpa's hours drawn as a forecast),
the visibility and the thunderstorm risk; and the model, its run, its age and
how far it is trusted. Each group lists its facts as label–value rows, and the
groups sit side by side as the width allows.
Wind is in knots, waves in meters, visibility in meters below a nautical mile and in nautical miles above, pressure in
hPa and rain in millimeters; the bar writes each unit from the catalog and each number in the crew's language.
Directions are degrees true and name the bearing the wind, waves or swell come from, as the forecast does; the arrow
points the other way, the way the water and air move. The vessel's own limits come in as limits, and a value at or
over one is drawn amber with a warning shape and a short word ("Reef", "Heavy sea", "Fog", "Fast fall"), named in
full for a screen reader. Amber stays on that value: the explanation beside it is plain text. Beside the control the
summary is two groups, the weather now and the outlook; the outlook shares the line at its right end where the bar is
wide enough and takes its own line from the left where it is not. The summary is a status region; the control and
the detail sit outside it, so opening the detail is not announced and a weather update does not read the control
out.
Examples
Collapsed
The bar starts closed. The line carries the glance; "Forecast details" opens the rest. Pass defaultOpen to start
open, or open with onOpenChange to hold the state yourself.
Code
import { WeatherBar } from "@bosunkit/components/weather-bar";
import type { ReactElement } from "react";
export const description: string =
"The bar as it first draws: the weather now on one line and a control that opens the forecast, sea state and " +
"model run under it.";
export default function Collapsed(): ReactElement {
return (
<WeatherBar
current={{
description: "Partly cloudy",
wind: "14 kn, gusts 19 kn",
conditions: "steady",
weatherCode: 2,
windFromDeg: 250,
}}
forecasts={[
{ period: "+6H", wind: "12–18 kn", conditions: "" },
{ period: "+12H", wind: "15–22 kn", conditions: "" },
]}
temperature="17 °C"
pressure="1016 hPa"
seaStateText="1.4 m"
days={[
{
day: "Mon 13",
weatherCode: 2,
cloudCoverPct: 40,
windMinKn: 12,
windMaxKn: 18,
windFromDeg: 250,
gustMaxKn: 23,
},
{
day: "Tue 14",
weatherCode: 3,
cloudCoverPct: 90,
windMinKn: 15,
windMaxKn: 22,
windFromDeg: 240,
gustMaxKn: 29,
},
]}
sea={{ waveHeightM: 1.4, wavePeriodS: 7, waveFromDeg: 255, douglas: 4 }}
model={{ name: "ICON-EU", ageHours: 2, confidence: 0.85 }}
limits={{ reefWindKn: 20, heavySeaM: 3 }}
/>
);
}
Expanded
Opened, the detail lays its groups side by side as the width allows and stacks them on a phone. A quiet forecast draws no amber at all.
Code
import { WeatherBar } from "@bosunkit/components/weather-bar";
import type { ReactElement } from "react";
export const description: string =
"A settled day at anchor in the Ría de Arousa, opened: two quiet days ahead, a slight sea, a steady barometer and a " +
"fresh model run.";
export default function Expanded(): ReactElement {
return (
<WeatherBar
current={{
description: "Clear",
wind: "8 kn, gusts 12 kn",
conditions: "easing",
weatherCode: 0,
windFromDeg: 20,
}}
temperature="21 °C"
pressure="1022 hPa"
seaStateText="0.6 m"
days={[
{
day: "Sat 18",
weatherCode: 0,
cloudCoverPct: 5,
windMinKn: 6,
windMaxKn: 12,
windFromDeg: 20,
gustMaxKn: 16,
waveHeightM: 0.7,
},
{
day: "Sun 19",
weatherCode: 1,
cloudCoverPct: 25,
windMinKn: 8,
windMaxKn: 14,
windFromDeg: 350,
gustMaxKn: 19,
waveHeightM: 0.9,
},
]}
sea={{
waveHeightM: 0.6,
wavePeriodS: 5,
waveFromDeg: 15,
swellHeightM: 0.8,
swellPeriodS: 11,
swellFromDeg: 300,
douglas: 3,
}}
pressureTrendHpa3h={0.4}
visibilityM={18500}
model={{ name: "ICON-EU", run: "06:00 UTC", ageHours: 1.5, confidence: 0.9 }}
limits={{ reefWindKn: 20, heavySeaM: 3 }}
defaultOpen
/>
);
}
Passage forecast with a gale day
days gives a row per day. The daily forecast carries the strongest wind and gust, the prevailing direction and
the weather code; the lightest wind, the highest waves, the rain, the cloud cover, the lowest visibility and the
hourly hours series are the caller's reduction of each day's hours. The gale day reaches the reef limit of 20 kn
and the heavy-sea limit of 3 m, each value carries its own mark, and the trends show when in the day the wind and
the sea build.
Code
import { WeatherBar } from "@bosunkit/components/weather-bar";
import type { ReactElement } from "react";
export const description: string =
"Four days of a Biscay passage against the vessel's reef limit of 20 kn and heavy-sea limit of 3 m: Wednesday's " +
"gale reaches both, Thursday's sea stays over the heavy-sea limit after the wind drops.";
export default function PassageGale(): ReactElement {
return (
<WeatherBar
current={{
description: "Cloudy",
wind: "16 kn, gusts 22 kn",
conditions: "building",
weatherCode: 3,
windFromDeg: 240,
}}
days={[
{
day: "Tue 14",
weatherCode: 3,
cloudCoverPct: 90,
windMinKn: 14,
windMaxKn: 19,
windFromDeg: 240,
gustMaxKn: 25,
waveHeightM: 2.2,
precipitationMm: 1.2,
hours: {
windKn: [14, 15, 16, 17, 19, 18, 17, 16],
gustKn: [19, 20, 22, 23, 25, 24, 23, 22],
waveHeightM: [1.9, 2.0, 2.0, 2.1, 2.2, 2.2, 2.2, 2.2],
},
},
{
day: "Wed 15",
weatherCode: 65,
cloudCoverPct: 100,
windMinKn: 27,
windMaxKn: 39,
windFromDeg: 220,
gustMaxKn: 51,
waveHeightM: 5.1,
precipitationMm: 21.7,
hours: {
windKn: [27, 30, 34, 37, 39, 38, 34, 30],
gustKn: [36, 40, 45, 49, 51, 50, 45, 40],
waveHeightM: [2.6, 3.2, 3.9, 4.5, 5.1, 5.0, 4.6, 4.1],
},
},
{
day: "Thu 16",
weatherCode: 80,
cloudCoverPct: 65,
windMinKn: 15,
windMaxKn: 19,
windFromDeg: 285,
gustMaxKn: 30,
waveHeightM: 3.6,
precipitationMm: 4.4,
hours: {
windKn: [19, 18, 17, 17, 16, 16, 15, 15],
gustKn: [30, 28, 26, 25, 24, 23, 22, 21],
waveHeightM: [3.6, 3.5, 3.4, 3.3, 3.2, 3.1, 3.0, 2.9],
},
},
{
day: "Fri 17",
weatherCode: 2,
cloudCoverPct: 40,
windMinKn: 10,
windMaxKn: 15,
windFromDeg: 300,
gustMaxKn: 20,
waveHeightM: 2.0,
precipitationMm: 0,
hours: {
windKn: [15, 14, 13, 12, 12, 11, 10, 10],
gustKn: [20, 19, 18, 17, 16, 15, 14, 14],
waveHeightM: [2.0, 1.9, 1.8, 1.7, 1.6, 1.5, 1.5, 1.4],
},
},
]}
sea={{ waveHeightM: 2.2, wavePeriodS: 8, waveFromDeg: 245, douglas: 4 }}
limits={{ reefWindKn: 20, heavySeaM: 3 }}
defaultOpen
/>
);
}
Rough sea
sea gives the significant wave height with its period and direction, the swell apart from it, and the Douglas
code bosund derives from the height. Waves at the heavy-sea limit are marked like a forecast day.
Code
import { WeatherBar } from "@bosunkit/components/weather-bar";
import type { ReactElement } from "react";
export const description: string =
"A rough sea off Cape Finisterre: 3.8 m of wind sea from the southwest on a long northwesterly swell, over the " +
"vessel's heavy-sea limit of 3 m.";
export default function RoughSea(): ReactElement {
return (
<WeatherBar
current={{
description: "Rain",
wind: "27 kn, gusts 38 kn",
conditions: "steady",
weatherCode: 63,
windFromDeg: 215,
}}
seaStateText="3.8 m"
sea={{
waveHeightM: 3.8,
wavePeriodS: 9,
waveFromDeg: 220,
swellHeightM: 3.1,
swellPeriodS: 14,
swellFromDeg: 300,
douglas: 5,
}}
limits={{ heavySeaM: 3 }}
defaultOpen
/>
);
}
Stale model run
model names the model, the run time with its reference and the age in hours. From 12 hours, where the forecast
analysis starts calling a forecast stale, the age turns amber and the bar asks for a newer forecast.
Code
import { WeatherBar } from "@bosunkit/components/weather-bar";
import type { ReactElement } from "react";
export const description: string =
"Two days out of satellite range: the last GRIB file is a GFS run 31 hours old, so the bar calls it out of date " +
"and the confidence has fallen to 30%. A GRIB file carries no weather code, so the sky comes from its cloud cover.";
export default function StaleModel(): ReactElement {
return (
<WeatherBar
current={{
description: "Cloudy",
wind: "12 kn, gusts 17 kn",
conditions: "",
cloudCoverPct: 80,
windFromDeg: 60,
}}
days={[
{ day: "Thu 16", cloudCoverPct: 85, windMinKn: 10, windMaxKn: 16, windFromDeg: 60, gustMaxKn: 21 },
{ day: "Fri 17", cloudCoverPct: 40, windMinKn: 12, windMaxKn: 18, windFromDeg: 45, gustMaxKn: 24 },
]}
model={{ name: "GFS", run: "06:00 UTC", ageHours: 31, confidence: 0.3 }}
defaultOpen
/>
);
}
Thunderstorm risk
convection carries CAPE in J/kg, the lifted index and the analysis's verdict, which also weighs the convective
inhibition, so the bar writes the verdict rather than judging CAPE alone. Visibility under the fog limit is marked,
and the pressure trend shows its direction with an icon.
Code
import { WeatherBar } from "@bosunkit/components/weather-bar";
import type { ReactElement } from "react";
export const description: string =
"A hot afternoon off the Costa Brava: thunderstorms in the forecast, 2800 J/kg of CAPE, a lifted index of -6.1, " +
"and visibility under the fog limit in the rain.";
export default function Thunderstorm(): ReactElement {
return (
<WeatherBar
current={{
description: "Thunderstorms",
wind: "9 kn, gusts 34 kn",
conditions: "gusty",
weatherCode: 95,
windFromDeg: 160,
}}
pressureTrendHpa3h={-1.8}
visibilityM={900}
convection={{ capeJPerKg: 2800, liftedIndex: -6.1, risk: "thunderstorm" }}
limits={{ pressureDropHpa3h: 3, fogVisibilityM: 1000 }}
defaultOpen
/>
);
}
No sea state from the source
A source without marine data leaves the waves out. The bar leaves out the waves column and says the source publishes none. MET Norway also publishes no visibility and no weather code, so the sky cell writes the cloud cover alone and draws the sky from it.
Code
import { WeatherBar } from "@bosunkit/components/weather-bar";
import type { ReactElement } from "react";
export const description: string =
"A forecast from MET Norway, which publishes no waves, no visibility and no weather code: the waves column is " +
"left out, the sky comes from the cloud cover, and the sea state says the source has none rather " +
"than showing an empty sea as calm.";
export default function NoSeaState(): ReactElement {
return (
<WeatherBar
current={{
description: "Overcast",
wind: "6 kn, gusts 11 kn",
conditions: "",
cloudCoverPct: 100,
windFromDeg: 200,
}}
days={[
{
day: "Mon 13",
cloudCoverPct: 96,
windMinKn: 4,
windMaxKn: 9,
windFromDeg: 200,
gustMaxKn: 12,
precipitationMm: 0.2,
hours: {
windKn: [4, 5, 6, 8, 9, 8, 6, 5],
gustKn: [7, 8, 9, 11, 12, 11, 9, 8],
precipitationMm: [0, 0, 0.1, 0.1, 0, 0, 0, 0],
cloudCoverPct: [100, 100, 98, 95, 95, 92, 94, 96],
},
},
{
day: "Tue 14",
cloudCoverPct: 55,
windMinKn: 8,
windMaxKn: 14,
windFromDeg: 230,
gustMaxKn: 19,
precipitationMm: 1.6,
hours: {
windKn: [8, 9, 11, 13, 14, 13, 11, 10],
gustKn: [12, 13, 15, 18, 19, 18, 16, 14],
precipitationMm: [0, 0.2, 0.6, 0.5, 0.2, 0.1, 0, 0],
cloudCoverPct: [80, 70, 60, 55, 45, 40, 45, 50],
},
},
]}
model={{ name: "MET Norway", ageHours: 2 }}
defaultOpen
/>
);
}
Controlled
Code
import { Button } from "@bosunkit/components/button";
import { WeatherBar } from "@bosunkit/components/weather-bar";
import { useState, type Dispatch, type ReactElement, type SetStateAction } from "react";
export const description: string =
"The detail held by the caller: a button outside the bar opens it too, and the bar's own control reports through " +
"onOpenChange.";
export default function Controlled(): ReactElement {
const [open, setOpen]: [boolean, Dispatch<SetStateAction<boolean>>] = useState<boolean>(false);
return (
<div style={{ display: "flex", flexDirection: "column", gap: "var(--space-sm)", width: "100%" }}>
<div>
<Button
onClick={(): void => {
setOpen(!open);
}}
>
{open ? "Hide the forecast" : "Show the forecast"}
</Button>
</div>
<WeatherBar
current={{ description: "Partly cloudy", wind: "13 kn, gusts 18 kn", conditions: "", weatherCode: 2 }}
days={[
{
day: "Sat 18",
weatherCode: 2,
cloudCoverPct: 40,
windMinKn: 10,
windMaxKn: 16,
windFromDeg: 270,
gustMaxKn: 21,
},
]}
open={open}
onOpenChange={setOpen}
/>
</div>
);
}
Single line
With nothing to open, the bar is the single line: no control and no detail.
Code
import { WeatherBar } from "@bosunkit/components/weather-bar";
import type { ReactElement } from "react";
export const description: string =
"The weather now with its air temperature, pressure and sea state, then the wind forecast for the next 6 and 12 hours.";
export default function Forecast(): ReactElement {
return (
<WeatherBar
current={{ description: "Partly cloudy", wind: "14kn gusts 19", conditions: "building" }}
forecasts={[
{ period: "+6H", wind: "12-18kn", conditions: "" },
{ period: "+12H", wind: "15-22kn", conditions: "" },
]}
temperature="17°C"
pressure="1012hPa"
seaStateText="1.2m"
/>
);
}
Data sources
Each forecast field the bar shows, and the providers in packages/bosun/weather/providers that fill it. A field a
provider lacks stays out of the props, and the bar leaves its cell, column or group out.
| Field | Open-Meteo | MET Norway | Stormglass | Local GRIB | HRRR |
|---|---|---|---|---|---|
| Wind, direction, gusts | yes | yes | yes | yes (gust if the file has it) | yes |
| Pressure | yes | yes | yes | yes | no |
| Temperature, humidity, dew point | yes | yes | yes | temperature, humidity | no |
| Total cloud cover | yes | yes | yes | if the file has it | no |
| Precipitation | yes | yes (next hour) | yes | if the file has it | no |
| Visibility | yes | no | yes | no | no |
| WMO weather code | hourly and daily | no | no | no | no |
| CAPE, inhibition, lifted index | yes | no | no | if the file has them | no |
| Waves and swell | marine API | no | yes | if the file has them | no |
| Daily summary, sunrise and sunset, UV | yes | no | hourly UV only | no | no |
No provider publishes the probability of precipitation or cloud cover split into low, middle and high, so the bar has no place for them. The ensemble and the model spread add the wind's spread across members and models.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| currentrequired | { description: string; wind: string; conditions: string; weatherCode?: number | undefined; cloudCoverPct?: number | undefined; windFromDeg?: number | undefined; } | – | The conditions now. |
| forecasts | readonly WeatherForecast[] | undefined | – | Forecast periods after now, in order. |
| temperature | string | undefined | – | The air temperature, formatted by the caller. |
| pressure | string | undefined | – | The barometric pressure, formatted by the caller. |
| seaStateText | string | undefined | – | The sea state, formatted by the caller; the bar puts the word "Sea" before it. |
| days | readonly WeatherDay[] | undefined | – | The forecast by day, in order, shown in the detail. With any detail the bar draws a control that opens it under the summary line; with none it stays a single line. |
| sea | WeatherSeaState | undefined | – | The sea state now, shown in the detail. Left out, the detail says the forecast source publishes no waves, as a source without marine data (MET Norway, a GRIB file without waves) leaves them out rather than sending zero. |
| pressureTrendHpa3h | number | undefined | – | The pressure change over the last 3 hours, in hPa, negative when falling. The SSE weather event does not carry
it; the caller takes it from the bus barometer's rate or the hourly forecast pressures. |
| pressureHourlyHpa | readonly (number | null)[] | undefined | – | The barometric pressure by the hour up to now, in hPa, oldest first, drawn as a small trend after the 3-hour change:
the bus barometer's record, or the forecast's surface_pressure_hpa for the hours already past. Its last value is
the pressure now. |
| pressureForecastHpa | readonly number[] | undefined | – | The forecast's surface_pressure_hpa for the hours after now, in hPa, drawn after pressureHourlyHpa as a
forecast, so a coming fall never reads as one already measured. |
| visibilityM | number | undefined | – | The visibility, in meters (visibility_m on the forecast hour), written in meters below a nautical mile and in
nautical miles above, rounded down so it never reads better than it is. Not on the SSE weather event yet. |
| convection | WeatherConvection | undefined | – | The thunderstorm risk now. Its CAPE and lifted index are on the forecast hour; not on the SSE event yet. |
| model | WeatherModelRun | undefined | – | The model run behind the forecast, its age and how far it is trusted. |
| limits | WeatherLimits | undefined | – | The vessel's limits the forecast days and the sea state are marked against; a limit left out marks nothing. |
| open | boolean | undefined | – | Whether the detail is open, for a caller that keeps the state; leave it out and the bar keeps its own. |
| defaultOpen | boolean | undefined | false | Whether the detail starts open when the bar keeps its own state. |
| onOpenChange | ((open: boolean) => void) | undefined | – | Called with the state the control asks for when the crew opens or closes the detail. |
| className | string | undefined | – | Classes added to the bar's own. |
Related
- Collapsible: the control and region the detail opens with.
- Data visualization: how forecast data is drawn.
- Typography: the monospace type the bar sets its values in.