Skip to content

React

<ml-map> is a custom element, so React renders it like any other tag. There is no wrapper component to install: register the element, import MapLibre’s CSS, and reference the typings once.

Terminal window
npm install @maplibre-yaml/core maplibre-gl
src/main.tsx
import { setWorkerUrl } from "maplibre-gl";
import workerUrl from "maplibre-gl/dist/maplibre-gl-worker.mjs?worker&url";
import "maplibre-gl/dist/maplibre-gl.css";
import "@maplibre-yaml/core/register";
// maplibre-gl 6 is ESM-only and cannot find its worker inside a bundle;
// point it there before the first map renders (v4/v5: drop these lines).
setWorkerUrl(workerUrl);
src/vite-env.d.ts
/// <reference types="@maplibre-yaml/core/react" />

The typings entry is types only (an empty module at runtime). It teaches React’s JSX about <ml-map>: src, config, a ref typed as MLMap (mapReady(), getMap()), slot children, and on React 19 the onml-map:* event props, each typed with its event’s detail.

examples/react is a Vite + React + TypeScript app that does everything on this page: a map from a YAML file with its params panel, one from a config object, events reaching React state, mapReady() through a ref, React-rendered controls in a map corner, mount and unmount under StrictMode, and the React 19 props. CI builds it against React 18 and React 19, type-checks it against both @types/react majors, and drives every build in a browser. The snippets in Web Components → React are files from that app, checked by a test, so they cannot drift from what CI runs.

React 19React 18
configthe object (keep it stable) or a JSON stringa JSON string only: config={JSON.stringify(doc)}
ml-map:* eventsonml-map:load={…} props, or a ref + addEventListenera ref + addEventListener
typingsobject config and typed event props allowedan object config is a type error

A JSON string plus a ref-based listener works on both majors, which is what most of the example uses. An equal config never rebuilds the map, so re-rendering a parent is free; a changed one rebuilds it.

The element class extends HTMLElement, which does not exist during server rendering, so register it from an effect in a "use client" component rather than with a top-level import. The server sends a plain <ml-map> tag, which upgrades once the import resolves. The snippet is in Web Components → Next.js.