cheesegrits/filament-google-maps
Filament Google Maps brings interactive Google Maps fields, columns, and widgets to Filament admin panels, with geocoding, marker and polygon editing, and map-based forms/tables for displaying and editing locations.
The package ships three things you will use constantly: a Map form field (pick a point), a MapColumn table column (show a point), and map widgets (dashboard/summary views). Install it against the matching Filament major version — the package tracks Filament releases, so check the version constraint before composer require cheesegrits/filament-google-maps. Since v5.0.2 the package also supports Laravel 13 (the v4 line was merged forward), so check both axes — Filament major and Laravel major — against the constraints in the release you are pulling. A package that supports your Filament version may still not support your Laravel version, and vice versa.
.env:GOOGLE_MAPS_API_KEY=AIza...
json column cast to an array holding lat/lng:// migration
$table->json('location')->nullable();
// model
protected $casts = ['location' => 'array'];
use Cheesegrits\FilamentGoogleMaps\Fields\Map;
Map::make('location')
->defaultLocation([51.5074, -0.1278])
->zoom(14)
->draggable()
->clickable();
First use case to prove the integration works: open the edit form, click the map to move the marker, save, then confirm the JSON in the DB changed. If the map is grey or throws a console error, it is almost always an API/key problem, not a Filament problem.
Map field as the system of record. Store lat/lng and let the field own the picking UX. Reverse geocoding is the killer feature — drag the pin, get structured address components written back to your model:
Map::make('location')
->draggable()
->clickable()
->autocomplete('address') // search box bound to your address field
->reverseGeocode([
'street' => '%S %n',
'city' => '%L',
'zip' => '%z',
'state' => '%A',
'country'=> '%c',
]);
This is the pattern for "store coordinates, display a human address." Format specifiers (%S, %n, %L, %z, %A, %c) map to Google address components — don't expect free-form strings.
Geocomplete when the address is the system of record. If your users think in addresses and the coordinates are derived, lead with Geocomplete and fan the result out to other fields:
Geocomplete::make('address')
->isLocation()
->updateLatLng('latitude', 'longitude')
->updateMap('location')
->placeId('google_place_id')
->countries(['gb'])
->types(['address']);
This avoids asking users to drag a pin, and gives you a place_id for cheap re-lookups later.
Table column for triage views. MapColumn is for scanning, not editing — a small inline map or pin that lets an operator confirm a record is geo-coded without opening it. Use it in list views where "is this address right?" is the daily question. Keep height() small and don't enable interactive maps on 50-row tables; the map loads are billed and the page gets heavy.
Widgets for coverage/ops dashboards. Widgets take markers from your own query, so the pattern is: build a query, map rows to marker arrays, hand them to the widget. This is where the package earns its keep for field-service, delivery, or store-locator style apps — one panel page showing every record missing coordinates is a genuinely useful internal tool.
Validation. Treat location as required-but-shaped: ->required() plus a rule that both lat and lng are present and numeric. A half-filled array is the most common data corruption this package produces.
.env, run php artisan config:clear. A stale cached config is the second most common "why is the map grey" cause.php artisan filament:assets and clear views. If the map renders once and then disappears after Livewire navigation, it's an asset/Alpine re-init issue — wire:ignore around the field and stable element IDs help.Map inside a Repeater or Builder will collide unless you give each instance a distinct ->id() derived from the item key. Two maps fighting over one DOM node is a confusing bug to chase.Map in a table; MapColumn has its own, smaller option set (showMap(), zoom(), height()). Reading the wrong class's docs wastes an afternoon.latitude/longitude columns, point the field at those rather than migrating to JSON — the field supports binding to discrete attributes, which keeps existing reporting queries intact.composer.json ("cheesegrits/filament-google-maps": "^5.0.2") and re-read the config/asset publishing step after any Laravel or Filament upgrade — a Laravel bump on a stale package constraint is the classic "works locally, fatal in CI" trap.How can I help you explore Laravel packages today?