Skip to content

Route Map

Draw a route on a tile-free map, with delayed stretches, a proposed reroute and cards anchored to stops.

import { RouteMap, RouteMapRoute, RouteMapStop, RouteMapTerrain } from '@youj/react'

Installation & usage

npm i @youj/react

For an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.

Use a route map where the question is where a load, a courier or a crew is on its way, which stretch is late and what the alternative would be. There are no tiles: land, water, parks and roads are abstract shapes in the theme's tones, so the routes are the loudest thing on it and nothing loads from a map provider. For a world view of where traffic comes from, use a Dot Map; for the same stops as a line of steps, a Stepper with a detour.

import { RouteMap, type RouteMapRoute, type RouteMapStop } from '@youj/react'

const stops: RouteMapStop[] = [
  { id: 'depot', name: 'Harbor depot', kind: 'origin', x: 12, y: 72, detail: 'Departed 09:14' },
  { id: 'truck', name: 'Load 4821', kind: 'current', x: 43, y: 45, card: <p>+47 min</p> },
  { id: 'summit', name: 'Summit DC', kind: 'destination', x: 86, y: 18, detail: 'ETA 15:49' },
]
const routes: RouteMapRoute[] = [
  { id: 'driven', status: 'done', path: ['depot', [24, 60], 'truck'] },
  { id: 'ahead', status: 'delayed', path: ['truck', 'summit'] },
  { id: 'reroute', status: 'proposed', label: 'Proposed via river road', path: ['truck', [66, 57], 'summit'] },
]

<RouteMap stops={stops} routes={routes} />

Stops sit at x and y, from 0 to 100 across and down the map. Their kind picks the marker: origin, stop, destination, or current for where the vehicle is now (it pulses). Any stop takes your own icon: the current one wears it on the accent, the others on an ink disc, as a fleet map's other trucks do. A route's path lists what it passes through: stop ids, and [x, y] waypoints to bend it along the roads; the line is smoothed through them. Its status is done (driven, quiet), on-time (ink), delayed (the danger tone) or proposed (a dotted line in the accent), and its label names it in the legend.

A stop's card is anchored beside its marker and always shown: an ETA, a warning, a reroute to approve. It sits toward the middle of the map unless cardSide says left, right, top or bottom. Anything else you lay over the map (a summary card, zoom controls) goes in children. terrain swaps the built-in coast for your own shapes, as path data in a 100 × 100 box; ratio sets the map's width over its height (16 / 10).

Reference

Propsstops, routes, terrain… (9)

Props

RouteMap props
PropType
stopsRequiredRouteMapStop[]–
routesRequiredRouteMapRoute[]–
terrainRouteMapTerrain

The land under the routes.

default DEFAULT_TERRAIN

DEFAULT_TERRAIN
valuestring | null

The picked stop's id (controlled); null for none.

–
defaultValuestring | null

The stop picked at first.

default null

null
onValueChange(id: string | null) => void–
legendboolean

Shows the legend of route states.

default true

true
rationumber

The map's width over its height.

default 16 / 10

16 / 10
labelstring

The map's accessible name. Default: the labels' "Route map".

–
childrenReactNode

Your own overlays on the map: controls, a summary card.

–
Other props pass through: extends ComponentProps<'div'>.

Stops

RouteMapStop props
PropType
idRequiredstring–
nameRequiredstring

"Harbor depot".

–
xRequirednumber

Across the map, 0–100 from its left edge.

–
yRequirednumber

Down the map, 0–100 from its top.

–
kindRouteMapStopKind
'origin''stop''destination''current'

Its marker.

default `stop`

`stop`
detailstring

A line said with its name and shown on hover: "Departed 09:14", "ETA 15:49".

–
iconReactNode

Your own marker face: a truck, a courier. The current position wears it on the accent; any other stop on an ink disc, in place of its dot.

–
cardReactNode

A card anchored beside the marker, always shown.

–
cardSide'left' | 'right' | 'top' | 'bottom'

Which side of the marker the card sits on. Default: left or right, toward the middle of the map.

–

Routes

RouteMapRoute props
PropType
idRequiredstring–
pathRequired(string | RouteMapPoint)[]

What it passes through, in order: stop ids, and waypoints as [x, y] (0–100) to bend it along the roads.

–
statusRouteMapStatus
'done''on-time''delayed''proposed'

default `on-time`

`on-time`
labelstring

Its name in the legend and the text alternative: "AI proposed via ring road". Default: its state's word.

–
StylingParts and data attributes

Styling

Parts: route-map, route-map-land, route-map-terrain, route-map-routes, route-map-route (with data-status), route-map-stop (with data-kind), route-map-marker, route-map-tag, route-map-card (with data-side) and route-map-legend. Lines keep their width at any size; the map never mirrors in RTL, since geography doesn't.

MotionDraw-in, markers, cards, pulse · reduced motion

Motion

Motion tokens
MomentTokens
Landfades in as the map scrolls into view
duration.slowease.enter

340ms · cubic-bezier(0.16, 1, 0.3, 1)

340mscubic-bezier(0.16, 1, 0.3, 1)
Routeseach draws along its length: driven, then on time, delayed and proposed, one state after another
duration.deliberateease.emphasized

560ms · cubic-bezier(0.6, 0, 0.1, 1)

560mscubic-bezier(0.6, 0, 0.1, 1)
Markersland as their first line starts; the destination settles
spring.snappy

0.2s, bounce 0

0.2s, bounce 0
Cardsrise in after their marker
duration.baseease.enter

220ms · cubic-bezier(0.16, 1, 0.3, 1)

220mscubic-bezier(0.16, 1, 0.3, 1)
Current positiona ring opens and fades, only while the map is on screen
duration.deliberateease.exit

560ms · cubic-bezier(0.4, 0, 1, 1)

560mscubic-bezier(0.4, 0, 1, 1)

Reduced motion

Everything is drawn in place, and the current position doesn't pulse.

Reduced motion

Routes, markers and cards are drawn in place and the current position holds still. The states read the same: color, dots and the legend carry them.

AccessibilityGroup, markers, text alternative

Accessibility

  • The map is a group named by label (default: the labels' "Route map").
  • Markers are buttons in stop order, named by place, kind and detail ("Summit DC, Destination, ETA 15:49"); pressing one picks it (aria-pressed), and hover or focus shows its name.
  • The routes and stops are written out for screen readers: every stop with its kind and detail, every route with its state and the stops it runs through ("Proposed via river road: Load 4821 → Summit DC").
  • Cards are ordinary content, read where they sit after their marker. The land, lines and legend are decorative.
  • Its words come from the labels (routeMap, routeOrigin, routeStop, routeDestination, routeCurrent, routeDone, routeOnTime, routeDelayed, proposed), translated by the language packs.