React Quickstart
Install
bash
npm install maplibre-gl react-map-glreact-map-gl is the idiomatic React wrapper. You can also use raw MapLibre.
Component (react-map-gl v8)
jsx
import { Map, Marker, NavigationControl } from 'react-map-gl/maplibre';
import 'maplibre-gl/dist/maplibre-gl.css';
export default function MapView() {
return (
<Map
initialViewState={{ longitude: 28.04, latitude: -26.20, zoom: 11 }}
style={{ width: '100%', height: '100vh' }}
mapStyle={`https://api.mapsfordevs.com/styles/standard.json?key=${import.meta.env.VITE_MFD_PUB_KEY}`}
>
<NavigationControl position="top-right" />
<Marker longitude={28.04} latitude={-26.20} color="#ef4444" />
</Map>
);
}Raw MapLibre with hooks
jsx
import { useEffect, useRef } from 'react';
import maplibregl from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
export function useMapLibre(opts) {
const ref = useRef(null);
const mapRef = useRef(null);
useEffect(() => {
if (!ref.current) return;
const map = new maplibregl.Map({ container: ref.current, ...opts });
mapRef.current = map;
return () => { map.remove(); mapRef.current = null; };
}, []);
return { ref, map: mapRef };
}
export default function MapView() {
const { ref } = useMapLibre({
style: `https://api.mapsfordevs.com/styles/standard.json?key=${import.meta.env.VITE_MFD_PUB_KEY}`,
center: [28.04, -26.20],
zoom: 11
});
return <div ref={ref} style={{ width: '100%', height: '100vh' }} />;
}Language picker
jsx
import { useEffect } from 'react';
function applyLang(map, lang) {
['place_label', 'transportation_name', 'poi_label'].forEach(layer => {
map.setLayoutProperty(layer, 'text-field', [
'coalesce', ['get', `name:${lang}`], ['get', 'name:latin'], ['get', 'name']
]);
});
}
export function LanguagePicker({ map, value, onChange }) {
useEffect(() => {
if (!map) return;
if (map.isStyleLoaded()) applyLang(map, value);
else map.once('styledata', () => applyLang(map, value));
}, [map, value]);
return (
<select value={value} onChange={e => onChange(e.target.value)}>
<option value="en">English</option>
<option value="de">Deutsch</option>
<option value="ja">日本語</option>
<option value="ar">العربية</option>
</select>
);
}Geocoding hook
jsx
import { useState, useCallback } from 'react';
export function useGeocode(apiKey) {
const [results, setResults] = useState([]);
const [loading, setLoading] = useState(false);
const search = useCallback(async (q) => {
setLoading(true);
try {
const r = await fetch(
`https://api.mapsfordevs.com/geocode/forward?q=${encodeURIComponent(q)}&limit=5`,
{ headers: { Authorization: `Bearer ${apiKey}` } }
);
const body = await r.json();
if (body.ok) setResults(body.items);
} finally {
setLoading(false);
}
}, [apiKey]);
return { results, loading, search };
}TypeScript
react-map-gl ships its own types. For raw MapLibre:
tsx
const mapRef = useRef<maplibregl.Map | null>(null);SSR (Next.js)
MapLibre is browser-only — wrap in dynamic import with ssr: false. See nextjs.md.