React
The React bindings live in a subpath of the same package and treat React as a peer dependency, so the core package stays framework-free.
npm install @waylocate/embed react
React 17 or newer is required.
ucba, a publicly available campus with the building muntz-hall and the room 170. Substitute your own campus slug once you have one. Slugs for your campus are listed in your Waylocate console, and the addressing rules are in the reference grammar.The component
<CampusMap> renders one div and mounts the map inside it. No transport
appears in your JSX, and the component does not accept an element: it creates
whatever it needs.
import { CampusMap } from "@waylocate/embed/react";
export function VenueMap() {
return (
<CampusMap
campus="ucba"
building="muntz-hall"
room="170"
className="h-[600px] w-full"
/>
);
}
Size the component yourself through className or style. It has no intrinsic
height.
Driving the map from props
Three props describe the current selection and are applied as commands whenever they change after the map has connected.
const [room, setRoom] = useState<string>();
<CampusMap campus="ucba" building="muntz-hall" room={room} />
Setting room to a new value sends selection.setRoom. Clearing your local
state back to undefined leaves the map where it is rather than deselecting, so
call map.selection.clear() through the ref if you want that.
The component tracks what it last applied and compares against what the map
reports, so a visitor selecting a room does not cause the component to command
the map back to its prop value. It also normalises the two spellings of a room
reference, meaning room="170" and room="muntz-hall/170" behave identically.
The remaining props describe the initial load and are read once. Changing any of
them, including campus, remounts the map.
Reaching the handle
Props cover selection. Everything else, including the camera, directions, state
reads, and event subscriptions, needs the handle. Take it from a ref or from
onReady.
import { useRef } from "react";
import { CampusMap } from "@waylocate/embed/react";
import type { WaylocateMap } from "@waylocate/embed";
export function VenueMap() {
const mapRef = useRef<WaylocateMap | null>(null);
return (
<>
<button
onClick={() => mapRef.current?.camera.fitTo("campus")}
>
Show whole campus
</button>
<CampusMap
ref={mapRef}
campus="ucba"
building="muntz-hall"
className="h-[600px] w-full"
onReady={(map) => console.log(map.capabilities)}
onSelectionChange={(selection, meta) => {
if (meta.source === "user") openPanel(selection.room);
}}
/>
</>
);
}
The ref is null until the map connects, which is why the click handler above
uses optional chaining rather than asserting.
Props
Initial load
Read once when the map mounts. Changing any of these remounts it.
| Prop | Type | Meaning |
|---|---|---|
campus | string | Campus slug. Required. |
ui | string | string[] | Chrome flags for the initial view |
from | string | Route origin, as a reference |
to | string | Route destination, as a reference |
nav | "preview" | "live" | Directions mode when from or to is set |
permissions | { geolocation?: boolean } | Capabilities granted to the map surface |
label | string | Accessible name for the map |
mapOrigin | string | Origin serving the map. Defaults to https://waylocate.com |
timeoutMs | number | How long to wait for the map to answer on connect |
commandTimeoutMs | number | Per-command timeout after connecting |
Live selection
Applied as commands whenever they change.
| Prop | Type | Meaning |
|---|---|---|
building | string | Building reference |
floor | string | Floor reference |
room | string | Room reference, bare or building-qualified |
Presentation and callbacks
| Prop | Type | Meaning |
|---|---|---|
className | string | Applied to the container element |
style | CSSProperties | Applied to the container element |
ref | Ref<WaylocateMap | null> | Receives the handle once connected |
onReady | (map) => void | Called once, after the handshake completes |
onError | (error) => void | Called on connection failure and on failed prop syncs |
onSelectionChange | (selection, meta) => void | Called on every selection change, including your own |
For events other than selection, subscribe through the handle with
map.on().
Custom layout with useCampusMap
The hook is what <CampusMap> is built from. Use it when you need the container
element to be something the component would not render, such as a node you are
also measuring or animating.
import { useRef } from "react";
import { useCampusMap } from "@waylocate/embed/react";
export function VenueMap() {
const containerRef = useRef<HTMLDivElement>(null);
const { map, status, error } = useCampusMap({
containerRef,
campus: "ucba",
building: "muntz-hall",
});
if (status === "error") return <p>Map unavailable: {error?.message}</p>;
return (
<div ref={containerRef} className="h-[600px] w-full">
{status === "connecting" && <Spinner />}
</div>
);
}
The hook accepts every <CampusMap> prop except className and style, plus
containerRef, and returns three values.
| Value | Type | Meaning |
|---|---|---|
status | "idle" | "connecting" | "ready" | "error" | Connection state |
map | WaylocateMap | null | The handle, once status is ready |
error | WaylocateError | null | Set when status is error |
Strict mode and teardown
Both the component and the hook mount through an AbortSignal. When React
invokes an effect twice in development, or unmounts before the connection
completes, the aborted attempt tears down the surface it created rather than
leaving an orphan behind. You do not need to guard against this yourself.
Next
- Controlling the map for everything the handle can do.
- SDK playground for a running version of the code on this page.