Headless Compounds
Compound components with zero markup or styling opinions — state and behavior only. Each binds to
the ambient controller from context (no separate props to wire it up) and each sub-component throws
a descriptive error ("X.Y must be used within <X.Provider>") if mounted outside its own
.Provider. Use these when you want the exact @openweather/maps-core behavior but none of the shipped
markup — the simple ./ui components (see Simple UI Kit) are built on the same state.
Timeline
import { Timeline } from '@openweather/maps-react';
<Timeline.Provider>
<Timeline.Track>
<Timeline.Ticks>
{(tick) => (
<span key={tick.time.toISOString()} style={{ left: `${tick.percent}%` }} />
)}
</Timeline.Ticks>
<Timeline.Scrubber />
</Timeline.Track>
<Timeline.AnimationControl />
</Timeline.Provider>;
| Part | Notes |
|---|---|
Timeline.Provider |
Binds to the ambient MapControllerProvider's timeline |
Timeline.Track |
The scrubbable axis container |
Timeline.Scrubber |
Draggable/keyboard-operable handle at the current time |
Timeline.Ticks |
Render-prop over tick marks ({ time, percent } each) |
Timeline.AnimationControl |
Play/pause |
Layers
import { Layers } from '@openweather/maps-react';
<Layers.Provider>
<Layers.List>
{(entries) =>
entries.map((entry) => (
<div key={entry.code}>
<Layers.Item code={entry.code} />
<Layers.ModelPicker code={entry.code} />
</div>
))
}
</Layers.List>
</Layers.Provider>;
| Part | Notes |
|---|---|
Layers.Provider |
Binds to the ambient LayersProvider's registry |
Layers.List |
Render-prop over LayerListEntry[] |
Layers.Item |
One layer's select/active/locked state, by code |
Layers.ModelPicker |
Per-layer model switcher (e.g. radar's nowcast), by code |
Search
import { Search } from '@openweather/maps-react';
<Search.Provider>
<Search.Bar>
<Search.Input />
<Search.Results>
{(result) => <Search.Item key={result.id} result={result} />}
</Search.Results>
</Search.Bar>
</Search.Provider>;
| Part | Notes |
|---|---|
Search.Provider |
Binds to the ambient MapControllerProvider's SearchController |
Search.Bar |
Wrapper connecting Search.Input's aria-controls to Search.Results' listbox id |
Search.Input |
Query input — core already debounces setQuery, so this doesn't add a second debounce layer |
Search.Results |
Render-prop over result list |
Search.Item |
Selecting a result flies the map to it by default |
Overlay state: useOverlays
There is no Overlays compound — overlay visibility/checked state is a plain hook instead,
useOverlays() from the main barrel (see Providers & Hooks), returning an
OverlaysSnapshot plus actions. <OverlayToggles> (the
simple kit's overlay control) takes an overlays store prop rather than reading this hook directly,
so it also works from a DOM-side createOverlayStore(engine) — see that page for the shared shape.
LockedLayerPrompt
Not a compound — a single standalone component pairing with Layers.Item's (or the simple
<LayerPanel>'s) locked-layer affordance:
<LockedLayerPrompt
layer={lockedLayer}
onDismiss={() => setLockedLayer(null)}
renderAction={(layer) => (
<a href={`/upgrade?feature=${layer.entitlementKey}`}>Upgrade</a>
)}
/>
| Prop | Type | Notes |
|---|---|---|
layer |
LayerMetadata | null |
The locked layer, or null to render nothing |
onDismiss?() |
Called when the dismiss control is activated | |
renderAction(layer) |
(layer: LayerMetadata) => ReactNode |
Your own upgrade CTA — the SDK has no opinion on your upgrade flow |
className? |
string |
Unstyled beyond data-owm-locked-layer-prompt* attributes — theme via CSS or className.