All integrations OpenLayers React WordPress API docs
react-map-gl if you prefer a declarative API. Both produce the map below.Install the library, then create the map in an effect and clean it up on unmount. No provider, no context, no token.
npm install maplibre-gl import { useEffect, useRef } from "react";
import maplibregl from "maplibre-gl";
import "maplibre-gl/dist/maplibre-gl.css";
const STYLE = "https://tiles.expressmaps.com/styles/standard.json?key=" + process.env.REACT_APP_EXPRESSMAPS_KEY;
export default function ExpressMap({ lng = -0.1276, lat = 51.5072, zoom = 12, marker = true }) {
const container = useRef(null);
useEffect(() => {
const map = new maplibregl.Map({ container: container.current, style: STYLE, center: [lng, lat], zoom });
map.addControl(new maplibregl.NavigationControl(), "top-right");
if (marker) new maplibregl.Marker().setLngLat([lng, lat]).addTo(map);
return () => map.remove();
}, [lng, lat, zoom, marker]);
return <div ref={container} style={{ width: "100%", height: 400 }} />;
} Use it anywhere: <ExpressMap lng={-0.1276} lat={51.5072} zoom={12} />. The key is public by design; restrict it to your domain in the console.
react-map-gl wraps MapLibre with React components for markers, popups and controls. Import from the /maplibre entry point.
npm install react-map-gl maplibre-gl import Map, { Marker, Popup, NavigationControl } from "react-map-gl/maplibre";
import "maplibre-gl/dist/maplibre-gl.css";
import { useState } from "react";
export default function OfficeMap() {
const [open, setOpen] = useState(false);
return (
<Map
initialViewState={{ longitude: -0.1276, latitude: 51.5072, zoom: 12 }}
style={{ width: "100%", height: 400 }}
mapStyle={"https://tiles.expressmaps.com/styles/standard.json?key=" + import.meta.env.VITE_EXPRESSMAPS_KEY}
>
<NavigationControl position="top-right" />
<Marker longitude={-0.1276} latitude={51.5072} onClick={() => setOpen(true)} />
{open && (
<Popup longitude={-0.1276} latitude={51.5072} onClose={() => setOpen(false)}>
Our office
</Popup>
)}
</Map>
);
}
MapLibre needs the browser, so load the component client-side only:
import dynamic from "next/dynamic";
const ExpressMap = dynamic(() => import("../components/ExpressMap"), { ssr: false }); Expose the key as NEXT_PUBLIC_EXPRESSMAPS_KEY. Because it is domain-restricted it is safe in client bundles.
Call map.setStyle(url) with another of the ten styles, or pass a new mapStyle prop. The tileset is shared, so switching is instant.