Skip to main content

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.

Examples use a demonstration campus. Every snippet on this site addresses 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.

PropTypeMeaning
campusstringCampus slug. Required.
uistring | string[]Chrome flags for the initial view
fromstringRoute origin, as a reference
tostringRoute destination, as a reference
nav"preview" | "live"Directions mode when from or to is set
permissions{ geolocation?: boolean }Capabilities granted to the map surface
labelstringAccessible name for the map
mapOriginstringOrigin serving the map. Defaults to https://waylocate.com
timeoutMsnumberHow long to wait for the map to answer on connect
commandTimeoutMsnumberPer-command timeout after connecting

Live selection

Applied as commands whenever they change.

PropTypeMeaning
buildingstringBuilding reference
floorstringFloor reference
roomstringRoom reference, bare or building-qualified

Presentation and callbacks

PropTypeMeaning
classNamestringApplied to the container element
styleCSSPropertiesApplied to the container element
refRef<WaylocateMap | null>Receives the handle once connected
onReady(map) => voidCalled once, after the handshake completes
onError(error) => voidCalled on connection failure and on failed prop syncs
onSelectionChange(selection, meta) => voidCalled 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.

ValueTypeMeaning
status"idle" | "connecting" | "ready" | "error"Connection state
mapWaylocateMap | nullThe handle, once status is ready
errorWaylocateError | nullSet 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