mapField
Pick a location on a Google Map. Stores latitude and longitude.
import { mapField } from 'nextjs-cms/core/fields'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
| Option | Type | Default | Description |
|---|---|---|---|
center | { lat, lng } | { lat: 39.8283, lng: 34.2716 } | Where the map is centered when there's no value yet. |
zoom | number | 3 | Initial zoom level. |
minZoom | number | 1 | How far out editors can zoom. |
latLngBounds | { north, south, west, east } | whole world | Restrict panning to an area. |
defaultValue | { lat, lng } | none | Pre-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
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>
)}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
| Column | VARCHAR(200) |
| Value | "lat,lng", e.g. 41.0082,28.9784 |