About react-map-gl
A repository-specific skill for building and reviewing MapLibre maps with `react-map-gl/maplibre` in FixMyBerlin / FMC projects. It documents conventions for React-based layers, events, map state, and testing-oriented inspection.
Key features
- 01Declarative source and layer patterns
- 02Map event and access conventions
- 03Loaded-state guards and debug exposure
- 04Feature selection and highlighting rules
- 05URL and viewport synchronization
Use cases
- 01Reviewing map source and layer changes
- 02Implementing feature click and hover handling
- 03Synchronizing map view with URL state
- 04Inspecting maps in agent or E2E tests
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ fixmyberlin/ fixmyskills --skill react-map-glAfter installing, type/react-map-glin Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
references/cursor-handling.mddeclarative-source-layer.mdfeature-state.mdflat-source-layer.mdinitial-view-state.mdinteractive-layer-ids.mdlayer-visibility-vs-unmount.mdmap-debug-exposure.mdmap-event-handlers.mdmap-images.mdmap-loaded-hook.mdmap-props-attribution-locale.mdmap-provider-wrapper.mdmap-url-state.mdDetails
From the project READMEreact-map-gl (MapLibre)
Conventions for react-map-gl/maplibre in FixMyBerlin / FMC projects. Import from react-map-gl/maplibre (not react-map-gl alone). Always import maplibre-gl/dist/maplibre-gl.css.
import 'maplibre-gl/dist/maplibre-gl.css'
import { MapProvider, Map, Source, Layer, useMap } from 'react-map-gl/maplibre'
Rules
| Topic | Rule |
|---|---|
| Sources / layers | <Source> + <Layer> in JSX only. Never map.addSource / map.addLayer (or remove*) for app data. Show/hide via layout.visibility or conditional render. |
| Layer structure | Flat siblings: one <Source> per source id, then <Layer> siblings (not nested). |
| Map events | Camera, pointer, load, tile lifecycle go on <Map> callback props. Not useEffect + map.on(…). useEffect only for React → map sync after load, or events without a Map prop (styleimagemissing). |
| Map access | Wrap app map UI in <MapProvider>. useMap() keyed by <Map id="…">. Never pass ref to <Map> for child access. |
| Map ready | Guard getStyle, queryRenderedFeatures, setFeatureState with useMapLoaded() (set in onLoad). |
| Debug exposure | In onLoad, call exposeMainMapForDebugging(event.target) (dev + Playwright only). Agents/tests read window.__mainMap. |
| Clicks | Layer ids in interactiveLayerIds; read event.features. No queryRenderedFeatures for primary click picking unless syncing URL features. |
| Feature highlight | Inspector/form truth in React; map tint via setFeatureState (paint) or React filter layer. Clear old state before applying new. |
| Attribution | attributionControl={false} on <Map>, <AttributionControl compact> as child. RTLTextPlugin={false} on every <Map>. |
| Viewport URL | zoom/lat/lng with zoom-aware rounding; write on onMoveEnd with history: 'replace'. |
| View state | Uncontrolled initialViewState seeded from URL; no mirrored viewState in React unless programmatic camera is needed. |
Which file to read
Read only the file for your task.
| Task | Read |
|---|---|
Add or review <Source> / <Layer>, remove addSource | declarative-source-layer.md, flat-source-layer.md |
| Show/hide layers | layer-visibility-vs-unmount.md |
Click/hover handler, choose a <Map> callback | map-event-handlers.md, interactive-layer-ids.md |
| Cursor over features | cursor-handling.md |
| Child/sibling needs the map instance | map-provider-wrapper.md |
getStyle / queryRenderedFeatures before load | map-loaded-hook.md |
| Agent/E2E map inspection | map-debug-exposure.md |
Selected/hovered feature highlight, setFeatureState | feature-state.md |
| Initial camera, fitBounds, bounds | initial-view-state.md |
?map= URL sync | map-url-state.md |
| Attribution, locale, RTL text plugin | map-props-attribution-locale.md |
Missing or dynamic icons, styleimagemissing, addImage | map-images.md |
All files are in references/. Pair with skills tanstack-router-conventions (?map= contract), zustand-state-management (useMapLoaded store), playwright-skill (E2E map helpers).
Review checklist
- No
addSource/addLayer/removeSource/removeLayer/setLayoutPropertyfor app data; flat<Source>+<Layer> -
<MapProvider>parent,useMap(), norefon<Map> - No
useEffect+map.onfor move/click/hover; viewport sync ononMoveEnd/onMove - Effects touching the map are React → map sync guarded by
mainMap+mapLoaded -
onLoadsets map-ready flag and callsexposeMainMapForDebugging - Every pickable layer id is in
interactiveLayerIds; handlers useevent.features - Old feature state cleared before new applied; features have ids (
promoteIdfor vector) -
attributionControl={false}+ child<AttributionControl>;RTLTextPlugin={false} - URL: shared
parseMapParam/serializeMapParam,replaceon pan/zoom, noencodeURIComponentaround the serialized value - Fixed icons via
useMapImages; dynamic icons viastyleimagemissinginuseEffectwithoff()cleanup andhasImageguard