Skip to content

React Router

View .md

Use instantmap-js/react in React Router v7 framework mode. The loader supplies the markers and the server renders the first image.

Terminal window
npm install instantmap-js

Return the markers from the route loader and render InstantMap in the component.

app/routes/home.tsx
import { InstantMap } from "instantmap-js/react";
import { listings } from "../listings";
import type { Route } from "./+types/home";
export function loader() {
return { listings };
}
export default function Home({ loaderData }: Route.ComponentProps) {
return (
<InstantMap
center={[-97.7431, 30.2672]}
zoom={11.5}
markers={loaderData.listings}
alt="Map of stays in Austin"
style={{ height: 560, borderRadius: 12 }}
/>
);
}

Keep ssr: true in react-router.config.ts.

react-router.config.ts
import type { Config } from "@react-router/dev/config";
export default { ssr: true } satisfies Config;

The server HTML contains an <img> whose src points at /static?. The browser paints it before JavaScript loads.

Use a ref for camera calls and onMarkerClick for clicks. Both work in the route component.

app/routes/home.tsx
import { useRef, useState } from "react";
import { InstantMap, type InstantMapHandle } from "instantmap-js/react";
import type { Marker } from "instantmap-js";
import type { Listing } from "../listings";
import type { Route } from "./+types/home";
export default function Home({ loaderData }: Route.ComponentProps) {
const { listings } = loaderData;
const map = useRef<InstantMapHandle<Listing>>(null);
const [clicked, setClicked] = useState<Marker<Listing> | null>(null);
return (
<>
<button onClick={() => map.current?.fitBounds(listings, { padding: 48 })}>
Show all {listings.length} stays
</button>
<p>{clicked ? `Opened ${clicked.title}` : "Click a pin"}</p>
<InstantMap
ref={map}
center={[-97.7431, 30.2672]}
zoom={11.5}
markers={listings}
onMarkerClick={setClicked}
alt="Map of stays in Austin"
style={{ height: 560, borderRadius: 12 }}
/>
</>
);
}
  • Setting ssr: false. The page then has no first image in its HTML.
  • Giving the map no height. It collapses to nothing.
  • Two copies of React on the server, which fails with Cannot read properties of null (reading 'useRef'). This happens when instantmap-js is installed from a local folder. Add resolve: { dedupe: ["react", "react-dom"] } and ssr: { noExternal: ["instantmap-js"] } to vite.config.ts.
Add an Instant Map to my React Router v7 framework-mode app. Follow https://instantmap.org/docs/frameworks/react-router.md exactly. Return the markers from the route loader, render InstantMap from instantmap-js/react in the component with a fixed height, and keep ssr: true. Build, start the server, and confirm the HTML from curl contains an img with /static? in its src.

examples/react-router on GitHub