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 4 Field Map Laravel Package

imumz/nova-4-field-map

A Laravel Nova 4 field for displaying and selecting locations on an interactive map inside Nova resources. Useful for geo-aware models that need coordinate or address input directly in the admin panel, with a simple field integration.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a small, single-purpose Nova 4 detail field: given a latitude and longitude it renders a read-only Leaflet map inside a resource detail page. It is not a form input — there is no search box, no draggable marker, no geocoding. Treat it as a display widget.

Install

composer require imumz/nova-4-field-map

Nova 4 packages normally ship pre-built assets in dist/. There is no service provider or config file to publish. If the map renders as an empty grey box after install, the compiled JS/CSS is missing — see Gotchas.

Where to look first

  1. src/Nova4FieldMap.php — the field class; this is the entire public API (a handful of setters plus component()).
  2. resources/js/components/DetailField.vue (or Field.vue) — how the map div, tile URL, and marker are wired.
  3. dist/js/field.js — confirms whether a build was shipped.
  4. package.json / webpack.mix.js — only relevant if you have to rebuild.

First use case

Show where a record is located on its detail page:

use Imumz\Nova4FieldMap\Nova4FieldMap;

public function fields(NovaRequest $request)
{
    return [
        // ... normal fields
        Nova4FieldMap::make('Location')
            ->onlyOnDetail()
            ->latitude('lat')
            ->longitude('lng'),
    ];
}

The exact setter names are the one thing to verify against the source — the class is tiny, so grep -n 'function ' src/Nova4FieldMap.php takes ten seconds and saves you a debugging session. Expect something close to latitude(), longitude(), zoom(), height(), tileUrl().

The realistic first win: you have a stores table with lat/lng columns (or a point column you resolve in an accessor) and you want an admin to visually confirm the pin is in the right place without leaving Nova.

Implementation Patterns

Detail-only placement, always. This is a display field; put it on the detail view and keep it off forms unless you pair it with an actual editing field:

Nova4FieldMap::make('Location')->onlyOnDetail(),

Use ->hideFromIndex() too if you're not certain the index component exists — a field with only a detail component will break the index table, not degrade gracefully.

Resolve coordinates in the model, not the field. The field almost certainly reads $this->resource->{$attribute}. If your coordinates live in one point column, on a related model, or need formatting, expose them as accessors and point the field at those:

// Model
public function getLatitudeAttribute(): ?float
{
    return $this->geo?->lat;
}

// Nova
Nova4FieldMap::make('Location')
    ->latitude('latitude')
    ->longitude('longitude')
    ->onlyOnDetail(),

This keeps the field dumb and lets you swap providers later.

Guard against the null/zero case. 0, 0 is a valid coordinate off the coast of Africa and is what a lot of "empty" decimal columns default to. Use ->resolveUsing() or ->displayUsing() (whichever the field supports) to return null when coordinates are absent, and let Nova's — placeholder do its job. Otherwise every unset record shows a map of the Gulf of Guinea and looks like a bug.

Pair it with an editing path. There is no form component here, so decide up front how coordinates get set:

  • Simplest: plain Number::make('Latitude') / Number::make('Longitude') form fields, map on detail only. Zero dependencies, works today.
  • Better UX: a third-party editable map field (there are a few Nova 4 options) on the form, and this package purely for the read-only detail view.
  • Cheapest: a Text field rendering a Google Maps / OSM link. If all you need is "click to open in maps", you do not need Leaflet at all.

Multiple maps per resource. Nothing should prevent two instances with different attributes (Warehouse, Billing address). Give each an explicit height so they don't collapse into each other visually.

Tile provider is your production decision. Leaflet's default is OpenStreetMap tiles, which are fine for internal/low-traffic Nova panels but carry attribution requirements and a usage policy that forbids heavy or commercial abuse. For anything customer-facing or high-volume, point the field at a paid/self-hosted tile source (Mapbox, Stadia, Protomaps, or your own tiles) — check whether the field exposes a tile URL setter; if not, it's a one-line change in the Vue component after forking.

Fork-first integration strategy. With 3 stars and 0 dependents, install it as a starting point, not a dependency you upgrade. composer require it, then either vendor the field class into app/Nova/Fields/ or maintain a fork under your own VCS entry in composer.json. That gives you a field you can actually patch when Leaflet or Nova changes.

Gotchas and Tips

The Leaflet CSS is the classic failure. Leaflet splits JS and CSS; a component that imports leaflet but not leaflet/dist/leaflet.css produces tiles that are scrambled, misaligned, or missing entirely, with no console error. If the map looks "almost right but broken", that's this.

Default marker icons 404 under any bundler. The well-known Leaflet + webpack/Vite issue: L.Icon.Default resolves marker-icon.png relative to the CSS URL and breaks. The component has to explicitly call L.Icon.Default.mergeOptions({ iconUrl, iconRetinaUrl, shadowUrl }) with imported asset URLs. If you see a shadowless missing-image marker, that's unpatched.

Container height. A Leaflet map inside a div with no explicit height renders zero pixels tall. If the field doesn't set a default, pass one via the field's height setter or override the component's style. This is the single most common "it's installed but I see nothing" cause after missing assets.

Asset build / dist freshness. The last release is March 2024. If the shipped dist/ is stale relative to resources/js, or absent, you must run npm install && npm run prod inside vendor/imumz/nova-4-field-map — which is wiped on every composer install. This alone is a strong argument for forking into your own repo or a path/VCS repository.

Nova upgrade fragility. The field targets Nova 4 specifically. Nova 4 → 5 changed asset handling and some field internals. Pin your Nova major version, and before any Nova upgrade, load one detail page with this field on it — a broken custom field often fails silently as a blank panel.

Coordinate type. MySQL DECIMAL(10,7) comes back as a string. Leaflet tolerates numeric strings, but if you do any arithmetic or comparison (e.g. if (! $lat)) cast to float in the accessor. Related: don't use if (! $lat) to detect missing data — 0.0 is falsy and legitimate.

Privacy and CSP. Leaflet fetches tiles from a third-party host on every detail page load, which leaks the viewer's IP to that provider and will be blocked by a strict Content-Security-Policy (img-src, connect-src). If your Nova panel sits behind a strict CSP, allowlist the tile host or self-host tiles — otherwise you get a blank map with only CSP violations in the browser console.

Debugging checklist, in order: ① browser console for JS errors and CSP violations ② Network tab for tile requests (200 vs blocked vs 404) ③ inspect the map div — does it have non-zero height? ④ confirm dist/js/field.js exists and is recent ⑤ console.log the resolved lat/lng inside the component. That sequence resolves ~95% of reports.

No community support net. Zero dependents and a single maintainer means no Stack Overflow answers, no issue-tracker archaeology. Budget an afternoon to actually read the ~100 lines of Vue and PHP. It's small enough that full comprehension is cheaper than debugging by guesswork — and you'll need that understanding the first time it breaks.

Escape hatch. If the map is a nice-to-have rather than core, a Text field with an <a href="https://www.openstreetmap.org/?mlat=...&mlon=..."> link delivers 80% of the value with none of the asset, CSP, or maintenance risk. Reach for this package when the visual pin genuinely matters — verifying delivery locations, checking geocoded addresses, spotting bad imports.

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.
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
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