PACKAGE
@element-editor/react
Element Editor's self-contained map editor in one React component. Owns the map, the toolbar, and all editor state. Zero configuration to start.
Screenshot: a full Element Editor mounted in a simple Next.js page. Streets basemap, floating drawing toolbar at the top centre, layers panel on the right, a sample polygon drawn with property form visible. Address bar shows 'localhost:3000'.
Install
npm install @element-editor/react maplibre-glUsage
import { ElementEditor } from '@element-editor/react'
import '@element-editor/react/style.css' // includes MapLibre's CSS
export default function App() {
return (
<div style={{ height: 600 }}>
<ElementEditor
onChange={(data) => console.log(data)}
/>
</div>
)
}That's it. The component mounts a MapLibre map with the Streets basemap (Dark in dark mode), renders the toolbar, and is ready to draw. No provider setup, no route configuration, no map-instance lifecycle management.
Using Leaflet instead
The default <ElementEditor> runs on MapLibre. (In the unpublished 0.1 pre-release it ran on Leaflet; see Migrating to 0.2 if you built against it.) For the Leaflet version, install @element-editor/adapter-leaflet leaflet react-leaflet and import from the /leaflet entry:
import { ElementEditor } from '@element-editor/react/leaflet'
import '@element-editor/react/leaflet/style.css'The props and ref are the same. tileLayer and renderer exist on the Leaflet entry only; on MapLibre use basemap and basemaps.
When to pick this package
Use @element-editor/react when:
- You don't have a map yet, or you're starting a new project with no constraint on the map library.
- You want everything assembled, including the toolbar, layers panel, data table, schema editor, and GeoJSON viewer.
- You don't need to customise the map layout. The component owns its viewport.
Use @element-editor/adapter-maplibre or @element-editor/adapter-leaflet instead when you already have a map instance you want to keep.
Key props
| Prop | Type | Description |
|---|---|---|
initialData | FeatureCollectionInput | GeoJSONFeatureInput | null | Pre-populate with existing GeoJSON. Also applied if it arrives after mount, while the editor is still empty. |
onChange | (data: FeatureCollection) => void | Fires on every committed change. |
onFeatureAdd | (feature: GeoJSONFeature) => void | Fires once per newly added feature. |
onFeatureUpdate | (id: string, feature: GeoJSONFeature) => void | Fires on commit (not during drag). |
onFeatureDelete | (id: string) => void | Fires once per deleted feature. |
onSelectionChange | (ids: string[]) => void | Fires whenever selection changes. |
onValidationError | (errors: Record<string, string[]>) => void | Fires when a submit is blocked by schema errors. |
tools | DrawTool[] | Restrict which tools appear in the toolbar. |
schema | Schema | Pre-load a single schema. |
readonly | boolean | Block every user edit. The ref keeps working. |
theme | 'light' | 'dark' | 'auto' | Light or dark mode only. Colours go through accentColor, style or CSS. |
accentColor | string | Brand colour, any CSS colour. The UI and map highlights follow it. |
featureColor | string | Default colour of every feature, any CSS colour. Colour single features with getFeatureStyle. |
style | React.CSSProperties | On the editor root; accepts CSS variables (--elm-accent, design tokens like --elm-surface), which also reach Element's portals. |
defaultBasemap | BasemapInput | Starting basemap: 'streets', 'terrain', 'light', 'dark', 'osm', 'auto' (default; follows the theme), a raster { url, attribution } or a MapLibre { style }. Use basemap + onBasemapChange to control it. |
basemaps | BasemapInput[] | false | Choices in the basemap picker. false hides it. |
maxFeatures | number | Cap the feature count. |
Full prop reference and ref API in the docs.
Imperative API via ref
import { useRef } from 'react'
import { ElementEditor, type ElementEditorRef } from '@element-editor/react'
export default function App() {
const ref = useRef<ElementEditorRef>(null)
return (
<>
<div style={{ height: 600 }}>
<ElementEditor ref={ref} />
</div>
<button onClick={() => ref.current?.getFeatureCollection()}>
Export
</button>
<button onClick={() => ref.current?.undo()}>Undo</button>
</>
)
}ElementEditorRef methods include getFeatureCollection, getFeature, setFeatureCollection, importGeoJSON, exportGeoJSON, addFeature, updateFeature(s), removeFeatures, select, setTool / getTool, getMap, getBasemap / setBasemap, flyTo, fitBounds, undo / redo, canUndo / canRedo, validate and submit.
Basemaps
Five basemaps are built in (Streets, Terrain, Light, Dark, OpenStreetMap), the vector ones served from OpenFreeMap, all with no API key, and a picker lets users switch. 'auto' follows the editor theme. Pass defaultBasemap to choose the starting one (or basemap + onBasemapChange to control it from your app), and basemaps to set what the picker offers:
import { ElementEditor } from '@element-editor/react'
<ElementEditor
defaultBasemap="auto"
basemaps={[
'auto', 'streets', 'dark',
{
id: 'satellite',
label: 'Satellite',
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',
attribution: 'Tiles © Esri',
},
]}
/>Pass basemaps={false} to hide the picker. Any raster tile URL or MapLibre style works. See the basemaps guide and map styles.
What's included
Everything from the Element Editor feature set, pre-assembled:
- Every drawing tool (including the OpenStreetMap picker)
- Vertex editing, selection & transform, snapping
- Boolean operations and geometry processing
- Measure
- Schemas — typed property fields with code-defined or in-app editing (S)
- Data table — spreadsheet view with inline editing (T)
- GeoJSON editor — two-way editing with JSON and schema validation (I)
- Import and export
- Keyboard shortcuts (every tool remappable)
- Theming (light, dark, auto, brand colour via
accentColoror--elm-accent, design tokens for fonts, radii, surfaces and more)
Versions and dependencies
- React and React DOM
^19.2— React 18 is not supported (the data table needs 19.2). - TypeScript — types ship in the package. With the
/leafletentry, also install@types/leaflet. - Peer deps:
react,react-dom^19.2,maplibre-gl^5.5. For the/leafletentry, also install@element-editor/adapter-leaflet,leaflet^1.9andreact-leaflet^5(optional peers). - Dependencies:
@element-editor/core,@element-editor/uiand@element-editor/adapter-maplibreare installed alongside, not bundled. ES modules plus.cjs; the geometry worker is inlined, so no bundler configuration is needed. - CSS: the stylesheet only styles the editor; it doesn't reset your page.
Ready to build?
Open the playground · Full API reference · See the adapter-maplibre package