USE CASE

A map editor that fits field-team workflows.

Typed forms for every feature. Standard GeoJSON out. Works with any tile source, including offline-cached tiles. Keyboard-first for fast data entry.

The problem

Field teams collect geographic data — inspection points, survey lines, boundary polygons, incident markers. Each item type needs its own fields. Teams often work with unreliable connectivity and on pre-cached basemaps. Generic map editors force every item through the same form and assume live tiles.

How Element Editor fits

Define one schema per item type. Field users draw with the matching tool (point for inspections, line for surveyed paths, area for boundaries) and pick the item type in the property panel, which then shows that schema's form. The data exports as standard GeoJSON — compatible with GIS systems, mobile-sync pipelines, and any backend that speaks RFC 7946.

Multiple item types, one editor. Each has its own schema.

What matters most for this use case

  • Multiple schemas per collection — points, lines, and polygons can all live in one FeatureCollection, each with its own schema (they travel as metadata.schemas).
  • Custom basemaps — add satellite imagery, pre-cached offline tiles, or a private internal tile server next to the built-in styles.
  • Keyboard shortcuts — every tool is one keystroke; field users spend their day in it.
  • Import and export — round-trip with a field app's sync layer; schemas survive.

A minimal setup

import { ElementEditor } from '@element-editor/react'
import '@element-editor/react/style.css'

export default function FieldApp() {
  return (
    <div style={{ height: 600 }}>
      <ElementEditor
        initialData={existingSurveyData}
        basemap={{
          id: 'field-imagery',
          label: 'Field imagery',
          url: 'https://offline-tiles.my-org.com/{z}/{x}/{y}.png',
          attribution: 'Internal imagery',
        }}
        basemaps={false}
        onChange={(data) => syncPendingChanges(data)}
      />
    </div>
  )
}

For offline-first setups, pair the onChange callback with a local IndexedDB store (or a service worker cache) so the sync to your backend happens when connectivity returns.

Ready to try it?