Add directions to React

Two addresses in, one line on the map, plus the distance and duration to label it with. The copied panel is the whole interaction, including geocoding both endpoints. The hook is the routing call on its own, for when the from and to already exist somewhere in your app.

Install

npx @unmap/cli add routing-panel

The panel

Like the geocoder, <RoutingPanel> is a child of <Map>: it draws onto the map it finds through map-context, and it resolves both text inputs to coordinates for you.

import { Map } from "@/components/ui/map";
import { RoutingPanel } from "@/components/ui/routing-panel";
 
export default function App() {
  const apiKey = import.meta.env.VITE_UNMAP_KEY as string;
 
  return (
    <div className="h-dvh">
      <Map apiKey={apiKey} center={[-114.07, 51.05]} zoom={11} className="h-full">
        <div className="absolute left-3 top-3 z-10 w-80">
          <RoutingPanel apiKey={apiKey} mode="auto" />
        </div>
      </Map>
    </div>
  );
}

Wait for ready before adding the source. A map that has not fired load has no style yet, and addSource on it throws.

Coordinates, not addresses

route takes [lng, lat] pairs. If your inputs are text, geocode them first, which is one extra call each and the reason the copied panel exists:

import { useGeocoder, useDirections } from "@unmap/react";
 
export default function RouteBetween() {
  const apiKey = import.meta.env.VITE_UNMAP_KEY as string;
  const { search } = useGeocoder({ apiKey });
  const { route } = useDirections({ apiKey });
 
  async function go(fromText: string, toText: string) {
    const [from] = await search(fromText, { limit: 1 });
    const [to] = await search(toText, { limit: 1 });
    if (!from || !to) throw new Error("could not resolve both endpoints");
    return route([from.lng, from.lat], [to.lng, to.lat], { mode: "auto" });
  }
 
  return <button onClick={() => void go("Calgary Tower", "Bow Valley Square")}>Route</button>;
}

What comes back

distanceMeters, durationSeconds, and a GeoJSON LineString. That is the whole result, so the label beside your line needs no second call. Five travel modes are available: auto, car, bicycle, pedestrian and truck, and an unknown one is a 400 rather than a silent car route.

The duration is a model of the road network with no live traffic in it. It is a good estimate of a quiet Sunday and an optimistic one of Friday at five.

Common problems

addSource throws. The map has not loaded. Gate on ready.

The route stops at the border. The graph is the Canada extract, so there is no cross-border routing. A pair of endpoints either side of the line has no answer rather than a detour.

A truck route is refused. mode: "truck" needs a valid vehicle profile; the routing docs list the dimensions and their limits.