USE CASE
Property boundaries that line up, with the data attached.
Magnetic snap to neighbouring parcels. Typed owner, zoning, and area fields. Clean polygons in, clean GeoJSON out.
The problem
Property-boundary data has two requirements most map editors don't serve together: topological cleanliness (adjacent parcels share exact vertices, not almost-shared ones) and structured ownership data (owner name, parcel ID, zoning class, recorded area). Solving one often means losing the other.
How Element Editor fits
Snapping is on by default — drawing against an existing parcel edge pulls the cursor to that exact vertex, so shared borders match to the last decimal. Typed schemas carry the data per parcel. Both ship in standard GeoJSON, ready for the cadastral system, the GIS import, or the public-records export.
Screenshot: a zoomed-in map showing ~30 adjacent parcels in different accent shades, clearly sharing vertices at borders. One parcel is selected; the form shows parcel_id, owner, zoning, area_sqm, recorded_at. The cursor is visible near a shared vertex with a snap indicator.
What matters most for this use case
- Snapping — the single feature that solves the topological-cleanliness problem.
- Schema-backed properties — parcel_id, owner, zoning, area as typed fields.
- Boolean operations — merge two parcels, subdivide one with slice.
- Vertex editing — precise adjustments; arc-length-based midpoint spacing handles dense border data (country edges, coastlines).
A minimal setup
import { ElementEditor } from '@element-editor/react'
import type { Schema } from '@element-editor/react'
import '@element-editor/react/style.css'
const parcelSchema: Schema = {
id: 'parcel',
name: 'Parcel',
fields: [
{ key: 'parcel_id', label: 'Parcel ID', type: 'text', required: true },
{ key: 'owner', label: 'Owner', type: 'text', required: true },
{ key: 'zoning', label: 'Zoning', type: 'select', required: true,
options: ['residential', 'commercial', 'industrial', 'agricultural', 'mixed'] },
{ key: 'area_sqm', label: 'Area (m²)', type: 'number', required: true, min: 0 },
{ key: 'recorded_at', label: 'Recorded', type: 'date', required: false },
{ key: 'notes', label: 'Notes', type: 'textarea', required: false },
],
}
export default function Parcels() {
return (
<div style={{ height: 600 }}>
<ElementEditor
schema={parcelSchema}
tools={['polygon', 'rectangle']}
onChange={(data) => syncToCadastralSystem(data)}
/>
</div>
)
}Snapping is on by default, so a new parcel lands exactly on its neighbour's vertices and edges. Hold ⌘ / Ctrl while clicking when a corner should sit near a boundary but not on it.