Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Nova Map Field Laravel Package

spiritsaint/nova-map-field

A Laravel Nova field that adds an interactive map input to your resources, letting editors pick a location and save its latitude and longitude coordinates to the model. Easy to drop into any Nova form.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and pin

composer require spiritsaint/nova-map-field
php artisan vendor:publish --tag=nova-map-field-config   # confirm tag in README
php artisan vendor:publish --tag=nova-map-field-assets   # only if dist/ isn't shipped

The v1.0.2 release is a patch on top of v1.0.1 with no documented breaking changes, so ^1.0 is a safe constraint for an existing install. Treat the empty changelog as a prompt to read the diff (v1.0.1...v1.0.2) before upgrading anything in production — patch releases in small Nova field packages are usually JS rebuilds, but occasionally recompile the compiled dist/field.js with a bumped laravel-nova peer.

Where to look first

  1. README.md — the authoritative list of fluent options; method names in this package are the thing most likely to drift from what you expect.
  2. src/MapField.php — the fields() payload and any resolve/fill logic. This tells you whether the field writes one column or splits into latitude/longitude.
  3. config/nova-map-field.php (after publishing) — provider, API key, default center, default zoom.
  4. resources/js/field.js / dist/js/field.js — what map library is actually bundled (Leaflet vs Google Maps matters for keys, CSP, and tile privacy).

First use case: a single location picker on a Resource

Add two nullable columns rather than one opaque JSON blob — it keeps the data queryable for "within N km" style filters later:

Schema::table('stores', function (Blueprint $table) {
    $table->decimal('latitude', 10, 7)->nullable();
    $table->decimal('longitude', 10, 7)->nullable();
});
use SpiritSaint\NovaMapField\MapField;

MapField::make('Location')
    ->latitude('latitude')
    ->longitude('longitude')
    ->defaultCenter(51.5074, -0.1278)
    ->zoom(12),

Confirm the exact fluent names against the README before wiring them into a resource — the field will silently render a default map if an option name is wrong, which is easy to mistake for a broken install.

Implementation Patterns

Separate columns vs a single JSON column. Prefer two decimal columns. A JSON column works for a quick prototype but you lose index-friendly geo queries, and ->resolveUsing() gets awkward when Nova's detail view expects a readable string.

Address search + coordinate capture. The common real-world pattern is "type an address, get a pin, store both". Keep the address in its own string column and let the map field own only the coordinates; don't try to round-trip a formatted address through the map component. If the field exposes a geocoder/search box, restrict it to the same provider you configured for the key, or you'll get mixed billing and inconsistent results.

Reactive forms. If latitude/longitude are also editable as plain Number fields, they will not update the map until the form reloads. Either make the map the sole editor, or hook ->dependsOn() / a Nova::$withRelations style refresh and accept the extra round trip. In practice the cleanest result is: map field visible and editable, coordinates displayed read-only in the detail view.

Filling from existing data. If your columns are named something other than latitude/longitude, map them explicitly — a mismatch here is the #1 cause of "the pin always lands at 0,0" after an edit:

MapField::make('Location')
    ->latitude('lat')
    ->longitude('lng')
    ->hideFromIndex(),

Index and detail views. A raw map per row will wreck index performance on tables over a few dozen rows. Use ->hideFromIndex() and render a cheap text column instead ("51.5074, -0.1278" via ->displayUsing()), or a static map thumbnail. On detail views a small read-only map is usually fine.

Validation. Add explicit rules on the underlying attributes; coordinate ranges are the only meaningful guard:

->rules('nullable', 'numeric', 'between:-90,90')   // latitude
->rules('nullable', 'numeric', 'between:-180,180')  // longitude

If the field supports "both or neither", enforce it with a custom rule rather than required_with, since 0 is a legal latitude and trips naive empty checks.

Imports and seeding. Because you own the columns, Model::create(['latitude' => ..., 'longitude' => ...]) works without touching the Nova layer. This is a strong argument for the two-column layout — artisan commands, seeders, and API endpoints all stay simple.

Testing. Nova field tests are usually Dusk-based; assert on the stored columns after a save rather than on map DOM, which is third-party and flaky. For unit-level coverage, assert the field's meta() payload contains your configured center and zoom — that catches config regressions without a browser.

Gotchas and Tips

API keys in the browser. Any map provider key configured here is shipped to the frontend. Restrict it by HTTP referrer in the provider console and use a separate key per environment. A leaked Nova key is a billing incident, not just an aesthetic one — this is the single highest-risk aspect of the package and worth checking on every upgrade.

Assets after deploy. Nova custom fields commonly break on deploy because the compiled dist/ isn't rebuilt or the published assets are stale. If the map renders as a blank grey box post-deploy, check public/vendor/nova-map-field and hard-refresh; also clear php artisan nova:publish / config cache. Run npm run prod in the package directory if dist/ is gitignored.

Precision. decimal(10,7) gives ~1cm at the equator and is plenty. float will round-trip inconsistently between MySQL and PHP and produce pins that shift by a few metres on every save. If you ever store a single point column instead, verify the package doesn't assume separate attributes.

Null Island. 0,0 is a valid coordinate off the coast of Africa, so "no location set" and "location is exactly 0,0" are indistinguishable if you default to zero. Default to null and make the field nullable; show "Not set" in the index rather than a pin at 0,0.

Render timing in modals and tabs. Maps mounted inside a Nova modal or a hidden tab initialise at zero height and render a partial or grey tile grid. If the package doesn't call invalidateSize() itself, this needs a custom field.js override — check resources/js/field.js before filing a bug.

CSP and tile hosts. If you run a Content-Security-Policy, add the tile host and the provider's script host to img-src/script-src. Symptoms are a map frame with no tiles and a wall of console CSP violations. This affects Leaflet/OSM and Google Maps equally.

Coordinate order. GeoJSON, Google Maps, and most APIs use latitude-first; some tile/bbox APIs use longitude-first. When you read these columns out into a geo query, be explicit about order or you'll ship a bug where every point is mirrored across the diagonal.

Field silently absent. If the map doesn't appear, check onlyOnForms/hideFromDetail/hideFromIndex combinations before suspecting the JS build — a ->hideFromIndex() + ->hideFromDetail() + ->onlyOnDetail() triple is a common copy-paste accident.

Extension points. The clean upgrade path for bespoke needs is ->meta([...]) to pass extra options into your own field component, plus a resources/js/field.js copy that extends the vendor component. Prefer that over forking the package, so patch releases like v1.0.2 stay trivially consumable. If you do fork, pin the commit and record why — small field packages change their internal laravel-nova mixin usage between minors.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels