nextjs-cms

mapField

Pick a location on a Google Map. Stores latitude and longitude.

import { mapField } from 'nextjs-cms/core/fields'
Warning:

The map uses the Google Maps JavaScript API. Set NEXT_PUBLIC_GOOGLE_MAPS_API_KEY in the admin's .env, or the field can't render.

Basic usage

mapField({ name: 'location' })

Editors click the map (or drag the marker) to set a point.

With every option

mapField({
    name: 'location',
    label: { en: 'Store location', ar: 'موقع المتجر' },
    required: true,
    order: 4,
    localized: false,
    conditionalRules: [{ field: hasPhysicalStore, condition: 'equals', value: true }],

    center: { lat: 41.0082, lng: 28.9784 }, // Istanbul
    zoom: 11,
    minZoom: 5,
    latLngBounds: { north: 42.2, south: 35.8, west: 25.6, east: 44.8 }, // Turkey
})

Options

OptionTypeDefaultDescription
center{ lat, lng }{ lat: 39.8283, lng: 34.2716 }Where the map is centered when there's no value yet.
zoomnumber3Initial zoom level.
minZoomnumber1How far out editors can zoom.
latLngBounds{ north, south, west, east }whole worldRestrict panning to an area.
defaultValue{ lat, lng }nonePre-placed marker on the create form. See the known issue below.

Plus the common options.

Options in detail

Keeping editors in the right area

For a business that only operates in one city or country, set center, a closer zoom, and latLngBounds, so editors don't have to scroll across the globe and can't drop a pin in the ocean:

mapField({
    name: 'branch_location',
    center: { lat: 25.2048, lng: 55.2708 }, // Dubai
    zoom: 10,
    minZoom: 8,
    latLngBounds: { north: 25.5, south: 24.7, west: 54.9, east: 55.7 },
})

defaultValue

Known issue:

The default is also written as the column's SQL DEFAULT, and an object is serialized as the text [object Object] there. Prefer center to guide editors, and leave defaultValue out until this is fixed.

Reading the value

The value is stored as a "lat,lng" string, for example 41.0082,28.9784. Parse it on your website:

type LatLng = { lat: number; lng: number }

export function parseLocation(value: string | null): LatLng | null {
    if (!value) return null
    const [lat, lng] = value.split(',').map(Number)
    return Number.isFinite(lat) && Number.isFinite(lng) ? { lat: lat!, lng: lng! } : null
}
const loc = parseLocation(store.location)

{loc && (
    <a href={`https://www.google.com/maps?q=${loc.lat},${loc.lng}`} target='_blank'>
        Open in Google Maps
    </a>
)}
Tip:

Need to query by distance ("stores within 10 km")? Also store the coordinates in two numberFields (or compute them in a hook) and index them. A text column can't be searched geographically.

Storage

ColumnVARCHAR(200)
Value"lat,lng", e.g. 41.0082,28.9784