Use getById when the interface follows one known dock:
import TflClient from "tfl-ts"
const tfl = new TflClient({
appKey: process.env.TFL_APP_KEY!,
})
const dock = await tfl.bikePoint.getById("BikePoints_237")
Search by radius when location helps someone compare nearby docks:
const nearby = await tfl.bikePoint.getByRadius({
lat: 51.508418,
lon: -0.067048,
radius: 500,
})
const data = nearby.places
Both methods return the public bike-point row shape, aliased here as
CycleHireDock.
The components do not fetch. Pass one or more bike-point rows as data. Add
full-screen layout, sheets, and floating cards in the app.
Most placements only need one dock. The detail view shows exact standard-bike,
e-bike, and empty-space counts with an occupancy bar.
import { CycleHireDocksDetail } from "@/components/tfl/cycle-hire/cycle-hire-docks"
export function DockAvailability({ dock }) {
return <CycleHireDocksDetail data={[dock]} hideHeader />
}
Use the map when position helps distinguish two or more docks. Pair it with
Detail when exact counts matter. In a Server Component, pass the same rows to
the named exports:
import {
CycleHireDocksMap,
CycleHireDocksDetail,
} from "@/components/tfl/cycle-hire/cycle-hire-docks"
export default async function Page() {
const data = await getNearbyBikePoints()
return (
<>
<CycleHireDocksMap data={data} />
<CycleHireDocksDetail data={data} hideHeader />
</>
)
}
CycleHireDocks.Map / CycleHireDocks.Detail read data from a Provider
instead of a prop. Resolve data in a Server Component, then pass it to a
Client Component that renders the compound:
"use client"
import { CycleHireDocks } from "@/components/tfl/cycle-hire/cycle-hire-docks"
export function DocksView({ data }) {
return (
<CycleHireDocks data={data}>
<CycleHireDocks.Map className="h-dvh" />
<CycleHireDocks.Detail hideHeader />
</CycleHireDocks>
)
}
Mount one surface or both.
The compound is a static property on a Client Component. Do not access
CycleHireDocks.Map from a Server Component module because React Server
Component references do not preserve static properties. Use the named exports
there instead.
Use the row alone when the surrounding interface already provides the heading
and layout:
import { CycleHireDockRow } from "@/components/tfl/cycle-hire/cycle-hire-docks"
export function DockAvailabilityRow({ dock }) {
return <CycleHireDockRow dock={dock} />
}
Broken slots are hidden by default. Pass showBroken on Detail or a row:
<CycleHireDocks.Detail hideHeader showBroken />
Use CycleHireDocksDisplay when dock information must fit the same 48px tile
rhythm as arrivals and status.
With several docks, the first tile shows the cycle roundel, heading, and page
indicator. The remaining tiles show docks. tiles={3} is one heading plus two
dock rows:
import { CycleHireDocksDisplay } from "@/components/tfl/cycle-hire/cycle-hire-docks"
export function DocksDisplay({ docks }) {
return <CycleHireDocksDisplay data={docks} tiles={3} behaviour="unattended" />
}
A single dock always uses one tile. The default roundel layout puts the
roundel, name, and counts on one line, with the slot strip along the bottom.
The stacked layout divides the tile into name, slot blocks, and counts:
<CycleHireDocksDisplay data={[dock]} />
<CycleHireDocksDisplay data={[dock]} singleDockVariant="stacked" />
Extra docks use manual pages by default. Unattended advances the same
non-overlapping pages automatically. Counts update in place; changed membership
and order wait for the next page boundary.
The map accepts the same tile unit for its height but does not join the dock
sequence:
<CycleHireDocksMap data={docks} tiles={6} />
| Prop | Type | Description |
|---|
data | readonly CycleHireDock[] | Dock rows in display order. |
tiles | number | Total tiles for a multi-dock display. Default 2. |
singleDockVariant | "roundel" | "stacked" | One-tile single-dock layout. Default "roundel". |
behaviour | "interactive" | "unattended" | Manual or automatic pages. Default "interactive". |
dwellMs | number | Unattended page interval. Default 10 seconds. |
startDelayMs | number | Delay before unattended paging starts. Default 0. |
idleReturnMs | number | Delay before an interactive display returns to page one. |
showBroken | boolean | Include broken slots in the counts and slot blocks. |
error | string | null | Show an error without changing the configured multi-dock height. |
className | string | Set width and placement styles. |
| Prop / API | Type | Description |
|---|
CycleHireDocks | { data, children } | Optional Provider root. Inject data once for child surfaces. |
CycleHireDocks.Map / CycleHireDocksMap | data?, tiles?, className? | OSM MapLibre surface. Markers need lat / lon on each row. |
CycleHireDocks.Detail / CycleHireDocksDetail | data?, showBroken?, hideHeader? | Expanding occupancy bars and counts. |
CycleHireDocks.Display / CycleHireDocksDisplay | data?, tiles?, singleDockVariant? | Fixed-height dock tiles with manual or unattended paging. |
showBroken | boolean | Include broken docks in counts and occupancy bars. Default false. |
Map markers show the proportion of standard bikes, e-bikes, and empty spaces.
They do not show exact counts. Each marker's accessible name contains the dock
name and counts. Labels move above the pin when the usual position would cover
another pin or leave the map.
Detail segment order: bike, e-bike, empty, then broken when showBroken. Accents on light UI: classic bikes red-500, e-bikes cyan-400, broken amber-300.
Map and Detail are not selection-linked. Compose that in the app if you need it.