A Filament Forms component that provides an interactive Leaflet map for selecting and storing geographical coordinates.
afsakar/filament-leaflet-map-picker is a Laravel package for a filament forms component that provides an interactive leaflet map for selecting and storing geographical coordinates..
It currently has 39 GitHub stars and 11.671 downloads on Packagist (latest version v3.0.0).
Install it with composer require afsakar/filament-leaflet-map-picker.
Discover more Laravel packages by afsakar
or browse all Laravel packages to compare alternatives.
Last updated
A Filament Forms component that provides an interactive Leaflet map for selecting and storing geographical coordinates.

{ lat, lng } state with legacy [lat, lng] and JSON string input support
| Package line | Filament | Laravel | PHP | Notes | | --- | --- | --- | --- | --- | | v3.0.0 target | 4.x | 12.x | 8.2+ | Supported in this line | | v3.0.0 target | 4.x | 13.x | 8.3+ | Supported in this line | | v3.0.0 target | 5.x | 12.x | 8.2+ | Host app must provide Livewire 4 and Tailwind CSS 4 | | v3.0.0 target | 5.x | 13.x | 8.3+ | Host app must provide Livewire 4 and Tailwind CSS 4 | | v2.x | 3.x | Existing v2 support matrix | See v2 docs | Filament 3 stays on the v2 line |
Filament 3 support is intentionally not part of the v3.0.0 package line. If you are staying on Filament 3, keep using the v2 releases.
Install the PHP package in your Filament app:
composer require afsakar/filament-leaflet-map-picker
The package auto-discovers its service provider. Filament assets are registered with FilamentAsset and loaded on demand through the component views' x-load, x-load-src, and x-load-css attributes, so you do not need to copy the compiled JS/CSS into your app for normal usage.
If you want Leaflet's image assets published locally, you can still publish them:
php artisan vendor:publish --tag="filament-leaflet-map-picker-assets"
You can publish translations with:
php artisan vendor:publish --tag="filament-leaflet-map-picker-translations"
Optionally, you can publish the views with:
php artisan vendor:publish --tag="filament-leaflet-map-picker-views"
Store the coordinates in a json or text column:
Schema::create('properties', function (Blueprint $table) {
$table->id();
$table->json('location')->nullable();
$table->timestamps();
});
Cast the attribute to array in your model:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Property extends Model
{
protected $fillable = [
'location',
];
protected $casts = [
'location' => 'array',
];
}
The canonical saved state for v3 is:
{ "lat": 41.0082, "lng": 28.9784 }
The package still reads these legacy inputs while you migrate existing data:
[41.0082, 28.9784]"{\"lat\":41.0082,\"lng\":28.9784}"New writes should use the canonical object shape. If you already cast the column to array, Laravel will persist the object-shaped array cleanly in a json column.
use Afsakar\LeafletMapPicker\LeafletMapPicker;
LeafletMapPicker::make('location')
->label('Property Location')
->height('500px')
->defaultLocation(['lat' => 41.0082, 'lng' => 28.9784])
->defaultZoom(15)
->draggable()
->clickable()
->myLocationButtonLabel('Go to My Location')
->geocoderEndpoint('https://nominatim.openstreetmap.org/search')
->geolocationTimeout(10000)
->geolocationHighAccuracy()
->hideTileControl()
->readOnly()
->tileProvider('openstreetmap')
->customTiles([
'mapbox' => [
'url' => 'https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}',
'options' => [
'attribution' => '© <a href="https://www.mapbox.com/">Mapbox</a>',
'id' => 'mapbox/streets-v11',
'maxZoom' => 19,
'accessToken' => 'YOUR_MAPBOX_TOKEN',
],
],
])
->customMarker([
'iconUrl' => asset('pin-2.png'),
'iconSize' => [38, 38],
'iconAnchor' => [19, 38],
'popupAnchor' => [0, -38],
]);
To show editable latitude and longitude inputs inside the picker, enable them on the picker and do not add separate sibling inputs for the same location state path:
LeafletMapPicker::make('location')
->showCoordinateInputs();
When enabled, the selected-location summary is hidden. The default is false, which keeps the summary visible.
The simplest canonical default location example is:
LeafletMapPicker::make('location')
->defaultLocation(['lat' => 41.0082, 'lng' => 28.9784]);
{ lat, lng } into the field state.{ lat, lng } into the field state.{ lat, lng } into the field state.{ lat, lng } into the field state.showCoordinateInputs() is enabled, editing either coordinate updates the map and the canonical field state after the input changes.use Afsakar\LeafletMapPicker\LeafletMapPickerColumn;
public function table(Table $table): Table
{
return $table->columns([
LeafletMapPickerColumn::make('location')
->label('Location')
->height('240px'),
]);
}
The column renders a compact thumbnail: it marks the location with a small dot instead of a pin and hides the attribution control, which would otherwise cover most of the tile. The default height is 50px.
The column is read-only. It accepts the canonical { lat, lng } object and legacy arrays or JSON strings. Null and invalid values use the configured default only for visual map placement; they are not shown as a selected record location and never change the row state.
use Afsakar\LeafletMapPicker\LeafletMapPickerEntry;
LeafletMapPickerEntry::make('location')
->label('Property Location')
->height('500px')
->defaultLocation(['lat' => 41.0082, 'lng' => 28.9784])
->tileProvider('openstreetmap')
->hideTileControl()
->customTiles([
'mapbox' => [
'url' => 'https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}',
'options' => [
'attribution' => '© <a href="https://www.mapbox.com/">Mapbox</a>',
'id' => 'mapbox/streets-v11',
'maxZoom' => 19,
'accessToken' => 'YOUR_MAPBOX_TOKEN',
],
],
])
->customMarker([
'iconUrl' => asset('pin-2.png'),
'iconSize' => [38, 38],
'iconAnchor' => [19, 38],
'popupAnchor' => [0, -38],
]);
openstreetmap and esri.https://nominatim.openstreetmap.org/search.Referer, User-Agent, API key, custom tile contract, attribution, or provider-specific compliance.User-Agent, and browser control over Referer is limited by the host app and browser policy.Run the package checks from the repository root:
composer install
npm install
npm run build
composer validate --no-check-publish
composer lint
composer phpstan
composer test
npm run test:js
Default:

Custom Marker:

Custom Tile:

Please see CHANGELOG for more information on what has changed recently.
Please see CONTRIBUTING for details.
Please review our security policy on how to report security vulnerabilities.
The MIT License (MIT). Please see License File for more information.