PHPackages                             eduardoribeirodev/filament-leaflet - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. eduardoribeirodev/filament-leaflet

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

eduardoribeirodev/filament-leaflet
==================================

Um widget de mapa para FilamentPHP.

v5.2.0(2w ago)2118.9k↑68.3%11MITPHPPHP ^8.1

Since Dec 10Pushed 2w ago3 watchersCompare

[ Source](https://github.com/eduardoribeirodev/filament-leaflet)[ Packagist](https://packagist.org/packages/eduardoribeirodev/filament-leaflet)[ RSS](/packages/eduardoribeirodev-filament-leaflet/feed)WikiDiscussions main Synced 2d ago

READMEChangelog (10)Dependencies (5)Versions (29)Used By (0)

Filament Leaflet
================

[](#filament-leaflet)

A powerful and elegant Leaflet integration for Filament PHP that makes creating interactive maps a breeze. Build beautiful, feature-rich maps with markers, clusters, shapes, and more using a fluent, expressive API.

Features
--------

[](#features)

- 🗺️ **Interactive Maps** - Full Leaflet integration with customizable tile layers
- 📍 **Markers &amp; Clusters** - Beautiful markers with popup/tooltip support and intelligent clustering
- 🎨 **Shapes** - Circles, polygons, polylines, rectangles, and circle markers
- 🎯 **Click Events** - Handle clicks on markers, shapes, and the map itself
- 📊 **GeoJSON Support** - Display density maps with custom color schemes
- 🔄 **Model Binding** - Automatically create markers from Eloquent models
- 🎨 **Multiple Tile Layers** - Switch between OpenStreetMap, Satellite, and custom layers
- 💾 **CRUD Operations** - Create markers directly from map clicks
- 🎭 **Customizable** - Extensive configuration options for every element

### Latest Features

[](#latest-features)

- **Form Field (MapPicker)** - Pick coordinates directly in forms with automatic latitude/longitude sync or JSON storage
- **Table Column (MapColumn)** - Display maps in Filament table columns for at-a-glance location visualization
- **Infolist Entry (MapEntry)** - Display read-only maps in Filament infolists
- **Model GeoJSON Files** - Automatic GeoJSON loading from models with `HasGeoJsonFile` trait
- **Layer Groups** - Organize markers and shapes with automatic coverage area calculation
- **Editable Layers &amp; Draw Control** - Edit markers and shapes directly on the map
- **Dynamic Icons** - Marker icons with automatic sizing and anchor point calculation
- **Heroicon Support** - Use Filament Heroicons directly in markers with automatic SVG rendering
- **Enhanced Shapes** - Factory methods (`fromRecord()`) for all shape classes with support for JSON columns
- **JSON Storage** - Store coordinates as JSON in single database column
- **Map Interaction Control** - Toggle dragging, zooming, and auto-recenter behavior
- **Static Maps** - Display read-only maps with automatic interaction disabling
- **Auto-Recenter** - Automatically recenter maps after users pan around
- **Mapbox Tile Layer Support** - New tile layer provider with configurable Access Token and tile size
- **Marker CRUD Actions** - Built-in view, edit, and delete actions for markers on the map
- **Coordinate DTO** - Improved handling of latitude/longitude pairs with dedicated DTO class
- **GeoSearch Input Field** - Geocoding search field with multiple provider support (Nominatim, Google Maps, Mapbox, Bing Maps)
- **Address Value Object** - Detailed address information from geocoding services
- **Layer Architecture** - Improved class hierarchy with `BaseLayer`, proper type hints, and Livewire compatibility

Installation
------------

[](#installation)

```
composer require eduardoribeirodev/filament-leaflet
```

Publish the assets:

```
php artisan vendor:publish --tag=filament-leaflet
```

This will publish the Leaflet assets used by the package.

Table of Contents
-----------------

[](#table-of-contents)

- [Installation](#installation)
- [Core Components](#core-components)
    - [Map Widget](#map-widget)
    - [MapPicker (Form Field)](#mappicker-form-field)
    - [GeoSearchInput (Form Field)](#geosearchinput-form-field)
    - [MapColumn (Table Column)](#mapcolumn-table-column)
    - [MapEntry (Infolist)](#mapentry-infolist)
- [Map Elements](#map-elements)
    - [Markers](#markers)
    - [Layer Groups](#layer-groups)
    - [Shapes](#shapes)
    - [Editable Layers](#editable-layers)
- [User Interactions](#user-interactions)
- [Advanced Features](#advanced-features)
- [Best Practices](#best-practices)
- [Configuration Reference](#configuration-reference)
    - [Method Reference](#method-reference)
    - [Concern Methods Reference](#concern-methods-reference)

Core Components
---------------

[](#core-components)

### Map Widget

[](#map-widget)

Create your first interactive map widget:

```
namespace App\Filament\Widgets;

use EduardoRibeiroDev\FilamentLeaflet\Widgets\MapWidget;
use EduardoRibeiroDev\FilamentLeaflet\Layers\Marker;

class MyMapWidget extends MapWidget
{
    protected ?string $heading = 'My Locations';
    protected array $mapCenter = [-23.5505, -46.6333];
    protected int $defaultZoom = 12;
    protected int $mapHeight = 600;

    protected function getMarkers(): array
    {
        return [
            Marker::make(-23.5505, -46.6333)
                ->title('São Paulo')
                ->popupContent('The largest city in Brazil'),
        ];
    }
}
```

[![Widget Example](images/widget.png)](images/widget.png)

#### Basic Configuration

[](#basic-configuration)

```
class MyMapWidget extends MapWidget
{
    // Display
    protected ?string $heading = 'Store Locations';
    protected int $mapHeight = 600;

    // Map center and zoom
    protected array $mapCenter = [-14.235, -51.9253];
    protected int $defaultZoom = 4;
    protected int $maxZoom = 18;
    protected int $minZoom = 2;
}
```

#### Map Interaction Control

[](#map-interaction-control)

Control how users interact with your map:

```
class MyMapWidget extends MapWidget
{
    // Allow/prevent dragging
    protected bool $mapDraggable = true;

    // Allow/prevent zooming (scroll wheel, pinch)
    protected bool $mapZoomable = true;

    // Auto-recenter after user pans (in milliseconds)
    // Set to null to disable
    protected ?int $recenterMapTimeout = 5000;  // Recenter after 5 seconds

    // Auto-center to user's current location
    protected bool $autoCenter = false;
}
```

**Static Maps** - Disable all interactions:

```
MapPicker::make('location')
    ->static()  // Equivalent to ->mapDraggable(false)->mapZoomable(false)
```

#### Controls

[](#controls)

Enable/disable map controls:

```
class MyMapWidget extends MapWidget
{
    protected bool $hasAttributionControl = true;
    protected bool $hasScaleControl = true;
    protected bool $hasZoomControl = true;
    protected bool $hasFullscreenControl = true;
    protected bool $hasSearchControl = true;

    protected bool $hasDrawMarkerControl = true;
    protected bool $hasDrawCircleMarkerControl = true;
    protected bool $hasDrawCircleControl = true;
    protected bool $hasDrawPolylineControl = true;
    protected bool $hasDrawRectangleControl = true;
    protected bool $hasDrawPolygonControl = true;
    protected bool $hasDrawTextControl = true;
    protected bool $hasEditLayersControl = true;
    protected bool $hasDragLayersControl = true;
    protected bool $hasRemoveLayersControl = true;
    protected bool $hasRotateLayersControl = true;
    protected bool $hasCutPolygonControl = true;
}
```

[![Map Controls Example](images/map-controls.png)](images/map-controls.png)

Conditionally show controls at runtime:

```
protected function hasDrawCircleControl(): bool
{
    return auth()?->user()?->is_admin;
}
```

#### Tile Layers

[](#tile-layers)

Choose from multiple providers or add custom layers:

```
use EduardoRibeiroDev\FilamentLeaflet\Enums\TileLayer;

class MyMapWidget extends MapWidget
{
    // Single layer
    protected TileLayer|string|array $tileLayersUrl = TileLayer::OpenStreetMap;

    // Multiple layers
    protected TileLayer|string|array $tileLayersUrl = [
        'Street Map' => TileLayer::OpenStreetMap,
        'Satellite' => TileLayer::GoogleSatellite,
        'Custom' => 'https://{s}.tile.custom.com/{z}/{x}/{y}.png',
    ];
}
```

#### Configuration

[](#configuration)

You can configure default values for the package in `config/filament-leaflet.php`:

```
return [

    'columns' => [ // Default column names for model binding (can be overridden in fromRecord() methods)
        'latitude' => 'lat',
        'longitude' => 'lng',
        'coords' => 'location',
        'radius' => 'radius',
        'title' => 'title',
        'description' => 'description',
        'bounds' => 'bounds',
        'points' => 'points',
    ],
    'sync_record_attributes' => true, // Auto-sync changes back to models
    'default_map_center' => [-14.235, -51.9253], // Default map center
];
```

Publish the configuration file:

```
php artisan vendor:publish --tag=filament-leaflet-config
```

[![Widget With Custom Tile Layers Example](images/tile-layers.png)](images/tile-layers.png)

**Available providers:** `OpenStreetMap`, `GoogleStreets`, `GoogleSatellite`, `GoogleHybrid`, `GoogleTerrain`, `EsriWorldImagery`, `EsriWorldStreetMap`, `EsriNatGeo`, `CartoPositron`, `CartoDarkMatter`, `Mapbox`

**Mapbox Tile Layer:**

To use Mapbox tiles, configure your access token in `.env` or `config/services.php`:

**Environment variables:**

```
MAPBOX_ACCESS_TOKEN=your_mapbox_access_token_here
MAPBOX_TILE_SIZE=512
```

**Or in config/services.php:**

```
'mapbox' => [
    'token' => env('MAPBOX_ACCESS_TOKEN'),
    'tile_size' => env('MAPBOX_TILE_SIZE', 512),
],
```

Then use the Mapbox tile layer in your widget:

```
use EduardoRibeiroDev\FilamentLeaflet\Enums\TileLayer;

class MyMapWidget extends MapWidget
{
    // Single Mapbox layer
    protected TileLayer|string|array $tileLayersUrl = TileLayer::MapboxStreets;
}
```

**Available Mapbox providers:**

- `TileLayer::MapboxStreets` - Streets layer
- `TileLayer::MapboxOutdoors` - Outdoors layer
- `TileLayer::MapboxLight` - Light layer
- `TileLayer::MapboxDark` - Dark layer
- `TileLayer::MapboxSatellite` - Satellite layer

**Or use multiple Mapbox layers:**

```
protected TileLayer|string|array $tileLayersUrl = [
    'Street Map' => TileLayer::OpenStreetMap,
    'Mapbox Streets' => TileLayer::MapboxStreets,
    'Mapbox Satellite' => TileLayer::MapboxSatellite,
    'Mapbox Outdoors' => TileLayer::MapboxOutdoors,
];
```

### MapPicker (Form Field)

[](#mappicker-form-field)

Add an interactive map inside Filament forms. It syncs map clicks to form fields and supports all MapWidget configuration methods.

```
use EduardoRibeiroDev\FilamentLeaflet\Fields\MapPicker;
use EduardoRibeiroDev\FilamentLeaflet\Enums\TileLayer;

MapPicker::make('location')
    ->height(300)
    ->center(-23.5505, -46.6333)
    ->zoom(11)
    ->autoCenter()  // Auto-center to user's location
    ->tileLayersUrl(TileLayer::OpenStreetMap)
    ->columnSpanFull()
```

[![Form Field Example](images/form-field.png)](images/form-field.png)

**Load GeoJSON:** Automatically loads from models with `HasGeoJsonFile` trait or `getGeoJsonUrl()` method:

```
use EduardoRibeiroDev\FilamentLeaflet\Concerns\HasGeoJsonFile;

class DeliveryZone extends Model
{
    use HasGeoJsonFile;

    public function getGeoJsonFileAttributeName(): string
    {
        return 'geojson_file';
    }

    public function getGeoJsonFileDisk(): ?string
    {
        return 's3';
    }

    public function getExpirationTime(): ?DateTime
    {
        return now()->addHour();
    }
}
```

**Customize pick marker:** Visual feedback when clicking the map:

```
MapPicker::make('location')
    ->pickMarker(fn(Marker $marker) => $marker->blue()->title('Selected'))
```

**Dynamic configuration:** Most methods accept closures:

```
MapPicker::make('location')
    ->center(fn() => [$lat, $lng])
    ->height(fn($record) => 300)
    ->zoom(fn($record) => $record->zoom_level)
    ->mapDraggable(fn($record) => $record->is_editable)
    ->recenterTimeout(fn($record) => $record->is_read_only ? 3000 : null)
```

### GeoSearchInput (Form Field)

[](#geosearchinput-form-field)

Search and select locations using multiple geocoding providers:

```
use EduardoRibeiroDev\FilamentLeaflet\Fields\GeoSearchInput;
use EduardoRibeiroDev\FilamentLeaflet\Enums\GeoSearchProvider;

GeoSearchInput::make('location')
    ->provider(GeoSearchProvider::Nominatim)  // Uses OpenStreetMap
    ->limit(10)                               // Max 10 results
    ->withAddressDetails()                    // Include structured address data
    ->language('ru')                          // Preferred language
    ->countryCodes('ru')                      // Restrict to Russia
    ->cacheResults(3600)                      // Cache for 1 hour
    ->textMode(false)                         // Stores full address instead of  coordinates
    ->columnSpanFull()
```

[![GeoSearch Input Example](images/geo-search-input.png)](images/geo-search-input.png)

**Supported Providers:**

- `Nominatim` (OpenStreetMap) - Free, no API key required
- `GoogleMaps` - Requires `GOOGLE_MAPS_API_KEY` environment variable
- `Mapbox` - Requires `MAPBOX_API_KEY` environment variable
- `BingMaps` - Requires `BING_MAPS_API_KEY` environment variable

**Advanced Configuration:**

```
// Restrict results to a geographic bounding box
GeoSearchInput::make('location')
    ->provider(GeoSearchProvider::Nominatim)
    ->viewbox(
        minLon: 19.0,   // West
        minLat: 41.0,   // South
        maxLon: 190.0,  // East
        maxLat: 82.0    // North
    )
    ->bounded(true)  // Strictly restrict to viewbox
    ->minSearchLength(3)  // Don't search until user types 3+ chars
    ->useShortLabels(true)  // "Moscow Kremlin" instead of full address
```

[![Short Labels GeoSearch Input Example](images/short-labels-geo-search-input.png)](images/short-labels-geo-search-input.png)

**Form Model Integration:**

The field returns a `GeoSearchResult` object containing:

- `coordinate` - The selected location's latitude/longitude
- `name` - Short place name
- `displayName` - Full address
- `address` - Structured address with country, city, postcode, etc.
- `type` - Location type (building, street, city, etc.)
- `addresstype` - More specific type (e.g. "tourism", "shop", "amenity")
- `boundingbox` - Geographic bounds of the location

```
use EduardoRibeiroDev\FilamentLeaflet\Fields\GeoSearchInput;
use EduardoRibeiroDev\FilamentLeaflet\ValueObjects\GeoSearchResult;

GeoSearchInput::make('location')->afterStateUpdated(function (callable $set, GeoSearchResult $state) {
    // Access the selected location's data
    $coordinate = $result->coordinate;  // Coordinate object with lat/lng
    $name = $result->name;              // Short name (e.g. "Eiffel Tower")
    $displayName = $result->displayName; // Full address
    $address = $result->address;        // Structured address data
    $type = $result->type;              // Location type (e.g. "tourism")
    $addresstype = $result->addresstype; // More specific type (e.g. "tourism", "shop", "amenity")

    // Example: Set a separate fields
    $set('full_address', $displayName);
    $set('city', $address->city);
    $set('country', $address->country);
    $set('type', $type);
    $set('addresstype', $addresstype);
})
```

**Address Components:**

The `Address` object provides structured address data:

```
$address = $result->address;

$address->country;       // "Brazil"
$address->countryCode;   // "BR"
$address->state;         // "São Paulo"
$address->city;          // "São Paulo"
$address->county;        // County name
$address->postcode;      // Postal code
$address->suburb;        // Suburb/neighborhood
```

### MapColumn (Table Column)

[](#mapcolumn-table-column)

Display maps directly in Filament table columns:

```
use EduardoRibeiroDev\FilamentLeaflet\Tables\MapColumn;
use EduardoRibeiroDev\FilamentLeaflet\Layers\Marker;

MapColumn::make('location')
    ->height(100)
    ->zoom(8)
    ->pickMarker(fn(Marker $marker) => $marker->black())
    ->static()    // Disable interactions in table preview
```

[![Table Column Example](images/table-column.png)](images/table-column.png)

Display circular maps for a unique visual style:

```
MapColumn::make('location')
    ->height(72)
    ->zoom(5)
    ->pickMarker(fn(Marker $marker) => $marker->iconSize([14, 25]))
    ->circular()  // Optional: circular display
```

[![Table Column Example](images/circular-table-column.png)](images/circular-table-column.png)

### MapEntry (Infolist)

[](#mapentry-infolist)

Display read-only maps in Filament infolists:

```
use EduardoRibeiroDev\FilamentLeaflet\Infolists\MapEntry;
use EduardoRibeiroDev\FilamentLeaflet\Layers\Marker;

MapEntry::make('location')
    ->height(284)
    ->zoom(10)
    ->pickMarker(fn(Marker $marker) => $marker->red())
    ->static()    // Disable interactions (enabled by default)
    ->columnSpanFull()
```

**Auto-recenter:** Maps automatically recenter after 3 seconds when users pan around. This provides a guided viewing experience while allowing temporary exploration:

```
    ->recenterTimeout(5000)  // Recenter after 5 seconds (null to disable)
```

[![Infolist Entry Example](images/infolist-entry.png)](images/infolist-entry.png)

Map Elements
------------

[](#map-elements)

### Markers

[](#markers)

#### Creating Markers

[](#creating-markers)

```
use EduardoRibeiroDev\FilamentLeaflet\Layers\Marker;
use Filament\Support\Colors\Color;

protected function getMarkers(): array
{
    return [
        Marker::make(-23.5505, -46.6333)->title('Simple marker'),
        Marker::make(-23.5212, -46.4243)->green()->title('Colored marker'),
        Marker::make(-23.5266, -46.5412)->icon('https://leafletjs.com/examples/custom-icons/leaf-red.png', [32, 72]),
        Marker::make(-23.5300, -46.6400)->violet()->icon('heroicon-user-circle')->title('Heroicon marker'),
    ];
}
```

[![Markers Example](images/markers.png)](images/markers.png)

#### Marker Icons

[](#marker-icons)

Markers support multiple icon types with different visual behaviors:

**Custom Icon URL** (replaces the entire marker):

```
Marker::make(-23.5505, -46.6333)
    ->icon('https://example.com/icon.png', [54, 54])
    ->title('Custom Icon Marker')
```

[![Custom Icon Marker Example](images/custom-marker.png)](images/custom-marker.png)

When using a custom icon URL, the entire marker is replaced with your custom image - the marker's color is ignored.

**Heroicons (Filament Icons)** (icon in center):

```
use Filament\Support\Icons\Heroicon;

Marker::make(-23.5505, -46.6333)
    ->icon(Heroicon::BuildingLibrary)        // Using Heroicon enum
    ->icon('heroicon-building-library')      // Using string
    ->heroicon('building-library')           // Using explicit heroicon() method
    ->iconSize([36, 54])
    ->title('Heroicon Marker')
    ->color(Color::Indigo);
```

[![Heroicon Marker Example](images/heroicon-marker.png)](images/heroicon-marker.png)

When using Heroicons, the marker keeps its default styled appearance with the color gradient, and the Heroicon is automatically rendered in the center in white. The marker's color settings (`.blue()`, `.red()`, etc.) are fully respected.

**Icon Appearance:**

- **Icon URL**: Fully replaces marker appearance (color is ignored)
- **Heroicon**: Keeps marker style (with color gradient) with the icon rendered in the center

#### Marker Colors

[](#marker-colors)

Markers accept colors in multiple formats:

**Using Color Class:**

```
Marker::make(-23.5505, -46.6333)
    ->color(Color::Blue)  // Color class constant
    ->blue()              // Convenience method
```

**Using string formats:**

```
Marker::make(-23.5505, -46.6333)
    ->color('#3388ff')           // Hex color
    ->color('rgb(51, 136, 255)') // RGB color
    ->color('oklch(59% 0.15 262)')  // OKLCH color
```

**Available convenience methods:** `blue()`, `red()`, `green()`, `orange()`, `yellow()`, `violet()`, `gray()`, `black()`, `gold()`, `randomColor()`

#### From Eloquent Models

[](#from-eloquent-models)

```
// Basic usage
Marker::fromRecord(
    record: $store,
    coordsColumn: 'coordinates',  // Column/attribute with Coordinate value object
    titleColumn: 'name',
    descriptionColumn: 'description',
    popupFieldsColumns: ['address', 'phone'],
    color: Color::Blue,
);

// With custom callback
Marker::fromRecord(
    record: $store,
    coordsColumn: 'coordinates',
    mapRecordCallback: function (Marker $marker, Model $record) {
        $marker->gold()->popupFields(['hours' => $record->hours]);
    }
);
```

**Note:** The `coordsColumn` parameter expects a `Coordinate` value object. Configure your model like this:

```
use EduardoRibeiroDev\FilamentLeaflet\ValueObjects\Coordinate;

class Store extends Model
{
    protected $casts = [
        'coordinates' => Coordinate::class,
    ];
}
```

### Layer Groups

[](#layer-groups)

Layer groups are a powerful way to organize and manage multiple layers on your map. They allow you to:

- **Toggle visibility** - Show/hide entire groups of layers at once
- **Organize layers** - Group related markers and shapes together
- **Improve performance** - Manage large datasets efficiently
- **Control layer management** - Add/remove layers from groups dynamically

#### Layer Group

[](#layer-group)

A simple container for organizing related layers. Perfect for grouping logically related markers and shapes without any automatic behavior:

```
use EduardoRibeiroDev\FilamentLeaflet\LayerGroups\LayerGroup;

protected function getMarkers(): array
{
    return [
        LayerGroup::make([
            Marker::make(-23.5505, -46.6333)->title('Store 1'),
            Marker::make(-23.5515, -46.6343)->title('Store 2'),
            Marker::make(-23.5525, -46.6353)->title('Store 3'),
        ])
        ->name('Active Stores')
        ->id('active-stores'),
    ];
}
```

**Using the `group()` helper method (shorthand):**

Instead of wrapping layers in `LayerGroup::make()`, you can use the `group()` method on any layer to automatically group multiple layers:

```
protected function getMarkers(): array
{
    return [
        Marker::make(-23.5505, -46.6333)
            ->title('Store 1')
            ->group('Active Stores'),

        Marker::make(-23.5515, -46.6343)
            ->title('Store 2')
            ->group('Active Stores'),

        Marker::make(-23.5525, -46.6353)
            ->title('Store 3')
            ->group('Active Stores'),
    ];
}
```

[![Layer Group Example](images/layer-group.png)](images/layer-group.png)

#### Feature Group

[](#feature-group)

Creates a polygon envelope around all layers in the group. This is useful for visualizing the coverage area or boundary of a set of points:

```
use EduardoRibeiroDev\FilamentLeaflet\LayerGroups\FeatureGroup;

protected function getMarkers(): array
{
    return [
        FeatureGroup::make([
            Marker::make(-23.5505, -46.6333)->title('Point 1'),
            Marker::make(-23.5515, -46.6343)->title('Point 2'),
            Marker::make(-23.5525, -46.6323)->title('Point 3'),
        ])
            ->name('Delivery Zone')
            ->blue()
            ->fillBlue()
            ->fillOpacity(0.3)
            ->weight(3)
            ->dashArray(5, 10),
    ];
}
```

[![Feature Group Example](images/feature-group.png)](images/feature-group.png)

#### Marker Cluster

[](#marker-cluster)

Groups nearby markers into clusters for better performance and visual clarity, especially with large datasets. Clusters automatically expand when zooming in:

```
use EduardoRibeiroDev\FilamentLeaflet\LayerGroups\MarkerCluster;

protected function getMarkers(): array
{
    return [
        MarkerCluster::make([
            Marker::make(-23.5505, -46.6333)->title('Location 1'),
            Marker::make(-23.5515, -46.6343)->title('Location 2'),
            Marker::make(-23.5525, -46.6353)->title('Location 3'),
        ])
        ->maxClusterRadius(80)
        ->showCoverageOnHover()
        ->name('Locations')
        ->spiderfyOnMaxZoom(),
    ];
}
```

[![Marker Cluster Example](images/marker-cluster.png)](images/marker-cluster.png)

**Cluster from Model:**

Create clusters directly from Eloquent models with powerful customization:

```
use App\Models\Store;
use EduardoRibeiroDev\FilamentLeaflet\Layers\Marker;
use Filament\Support\Colors\Color;

protected function getMarkers(): array
{
    return [
        MarkerCluster::fromModel(
            model: Store::class,
            coordsColumn: 'coordinates',  // Column/attribute with Coordinate value object
            titleColumn: 'name',
            descriptionColumn: 'description',
            popupFieldsColumns: ['address', 'phone'],
            color: Color::Green,
        )
        ->maxClusterRadius(60)
        ->disableClusteringAtZoom(15),
    ];
}
```

**Cluster with Query Modification:**

Filter and customize the query used to load markers:

```
MarkerCluster::fromModel(
    model: Store::class,
    coordsColumn: 'coordinates',
    modifyQueryCallback: function ($query) {
        return $query
            ->where('status', 'active')
            ->where('city', 'São Paulo')
            ->orderBy('name');
    },
    mapRecordCallback: function (Marker $marker, Model $record) {
        // Customize each marker based on record properties
        if ($record->isPremium()) {
            $marker->gold()->icon('/images/premium-icon.png');
        }

        // Add status-based styling
        match($record->status) {
            'open' => $marker->green(),
            'busy' => $marker->orange(),
            'closed' => $marker->red(),
            default => $marker->gray(),
        };

        // Add popup with custom fields
        $marker->popupFields([
            'manager' => $record->manager_name,
            'staff' => $record->staff_count . ' employees',
            'rating' => $record->rating . ' ⭐',
        ]);
    }
);
```

**Advanced cluster configuration:**

```
MarkerCluster::make($markers)
    ->maxClusterRadius(80)              // Cluster radius in pixels
    ->showCoverageOnHover(true)         // Highlight cluster area on hover
    ->zoomToBoundsOnClick(true)         // Zoom to cluster bounds when clicked
    ->spiderfyOnMaxZoom(true)           // Spread markers at max zoom
    ->removeOutsideVisibleBounds(true)  // Remove markers outside viewport for performance
    ->disableClusteringAtZoom(15)       // Stop clustering at zoom level 15+
    ->animate(true);                    // Animate cluster changes;
```

### Shapes

[](#shapes)

Draw various geometric shapes on your map:

#### Circles

[](#circles)

Circles with radius in various units:

```
use EduardoRibeiroDev\FilamentLeaflet\Layers\Shapes\Circle;

protected function getShapes(): array
{
    return [
        Circle::make(-23.5505, -46.6333)
            ->popupContent('10km radius coverage')
            ->title('Service Area')
            ->blue()
            ->fillBlue()
            ->fillOpacity(0.2)
            ->radius(10000)           // Radius in meters (default)
            ->radiusInKilometers(10)  // Radius in kilometers
            ->radiusInMiles(6.2)      // Radius in miles
            ->radiusInFeet(32808)     // Radius in feet
    ];
}
```

[![Circles Example](images/circle.png)](images/circle.png)

#### Circle Markers

[](#circle-markers)

Small circles with pixel-based radius (like markers but circular):

```
use EduardoRibeiroDev\FilamentLeaflet\Layers\Shapes\CircleMarker;

CircleMarker::make(-23.5505, -46.6333)
    ->radius(45) // Radius in pixels
    ->red()
    ->fillRed()
    ->weight(2)
    ->title('Point of Interest');
```

[![Circle Markers Example](images/circle-marker.png)](images/circle-marker.png)

#### Polygons

[](#polygons)

Draw custom polygons:

```
use EduardoRibeiroDev\FilamentLeaflet\Layers\Shapes\Polygon;

// Define a polygon area
Polygon::make(
    [-23.5505, -46.6333],
    [-23.5515, -46.6343],
    [-23.5525, -46.6323],
    [-23.5505, -46.6333], // Close the polygon
)
->green()
->fillGreen()
->fillOpacity(0.3)
->title('Delivery Zone')
->popupContent('We deliver to this area');

// Or build point by point
Polygon::make()
    ->addPoint(-23.5505, -46.6333)
    ->addPoint(-23.5515, -46.6343)
    ->addPoint(-23.5525, -46.6323)
    ->addPoint(-23.5505, -46.6333)
    ->blue();
```

[![Polygons Example](images/polygon.png)](images/polygon.png)

#### Polylines

[](#polylines)

Draw lines connecting multiple points:

```
use EduardoRibeiroDev\FilamentLeaflet\Layers\Shapes\Polyline;

// Route or path
Polyline::make(
    [-23.5505, -46.6333],
    [-23.5515, -46.6343],
    [-23.5525, -46.6353],
    [-23.5535, -46.6363],
)
->blue()
->weight(4)
->opacity(0.7)
->dashArray('10, 5')      // Dashed line
->smoothFactor(1.5)       // Smooth curves
->title('Delivery Route');

// Or build incrementally
Polyline::make()
    ->addPoint(-23.5505, -46.6333)
    ->addPoint(-23.5515, -46.6343)
    ->addPoint(-23.5525, -46.6353)
    ->red()
    ->weight(3);
```

[![Polylines Example](images/polyline.png)](images/polyline.png)

#### Rectangles

[](#rectangles)

Draw rectangular bounds:

```
use EduardoRibeiroDev\FilamentLeaflet\Layers\Shapes\Rectangle;

// Using corner coordinates
Rectangle::make(
    [-23.5505, -46.6333],  // Southwest corner
    [-23.5525, -46.6353]   // Northeast corner
)
->orange()
->fillOrange()
->fillOpacity(0.2)
->title('Restricted Area');

// Alternative syntax
Rectangle::makeFromCoordinates(
    -23.5505, -46.6333,    // Southwest lat, lng
    -23.5525, -46.6353     // Northeast lat, lng
)
->red();
```

[![Rectangles Example](images/rectangle.png)](images/rectangle.png)

#### Shapes from Eloquent Models

[](#shapes-from-eloquent-models)

All shape classes support `fromRecord()` factory methods for easy creation from database records:

```
use App\Models\DeliveryZone;
use EduardoRibeiroDev\FilamentLeaflet\Layers\Shapes\Circle;
use EduardoRibeiroDev\FilamentLeaflet\Layers\Shapes\Polygon;
use EduardoRibeiroDev\FilamentLeaflet\Layers\Shapes\Polyline;
use EduardoRibeiroDev\FilamentLeaflet\Layers\Shapes\Rectangle;
use EduardoRibeiroDev\FilamentLeaflet\Layers\Shapes\CircleMarker;

protected function getShapes(): array
{
    return DeliveryZone::all()->map(function ($zone) {
        // Circle from record
        return Circle::fromRecord(
            record: $zone,
            coordsColumn: 'center_coordinates',
            radiusColumn: 'coverage_radius_km',
            titleColumn: 'name',
            descriptionColumn: 'description',
            popupFieldsColumns: ['address', 'radius'],
        );
    })->all();
}
```

**Configure Your Model:**

```
use EduardoRibeiroDev\FilamentLeaflet\ValueObjects\Coordinate;

class DeliveryZone extends Model
{
    protected $casts = [
        'center_coordinates' => Coordinate::class,
    ];
}
```

Each shape type supports the `fromRecord()` method with common parameters:

- `record`: The Eloquent model instance
- `coordsColumn`: Column name for center coordinates (for Circle, CircleMarker) - expects a `Coordinate` value object
- `radiusColumn`: Column name for radius (for Circle, CircleMarker)
- `pointsColumn`: Column name for points array (for Polygon, Polyline)
- `boundsColumn`: Column name for bounds array (for Rectangle)
- `titleColumn`: Column name for the shape title
- `descriptionColumn`: Column name for the popup content
- `popupFieldsColumns`: Array of column names to include in popup
- `color`: Default color for the shape
- `syncRecord`: Whether to sync changes back to the record when edited (default: true from config)
- `mapRecordCallback`: Closure to customize the shape based on the record

##### Circle from Record

[](#circle-from-record)

```
Circle::fromRecord(
    record: $zone,
    coordsColumn: 'center',
    radiusColumn: 'coverage_radius_km',
    titleColumn: 'zone_name',
    descriptionColumn: 'zone_description',
    mapRecordCallback: fn(Circle $circle, $record) =>
        $circle->radiusInKilometers($record->coverage_radius_km)
);
```

##### Polygon from Record

[](#polygon-from-record)

```
// Assumes database structure: points => [[lat, lng], [lat, lng], ...]
Polygon::fromRecord(
    record: $zone,
    pointsColumn: 'boundary_points',
    titleColumn: 'zone_name',
    popupFieldsColumns: ['area_sqkm', 'population'],
);
```

##### Polyline from Record

[](#polyline-from-record)

```
// Store route as JSON array of [lat, lng] coordinates
Polyline::fromRecord(
    record: $deliveryRoute,
    pointsColumn: 'route_path',
    titleColumn: 'route_name',
    descriptionColumn: 'destination',
    mapRecordCallback: fn(Polyline $line, $record) =>
        $record->is_completed
            ? $line->green()->weight(2)
            : $line->red()->weight(3)
);
```

##### Rectangle from Record

[](#rectangle-from-record)

```
// Assumes database structure: bounds => [[lat1, lng1], [lat2, lng2]]
Rectangle::fromRecord(
    record: $territory,
    boundsColumn: 'service_bounds',
    titleColumn: 'territory_name',
    popupFieldsColumns: ['region', 'sales_person'],
);
```

#### Shape Styling

[](#shape-styling)

```
Circle::make(-23.5505, -46.6333)
    ->radius(5000)

    // Border styling
    ->color(Color::Blue)        // Border color
    ->weight(3)                 // Border width in pixels
    ->opacity(0.8)              // Border opacity (0-1)
    ->dashArray('5, 10')        // Dashed border pattern

    // Fill styling
    ->fillColor(Color::Green)   // Fill color
    ->fillOpacity(0.3)          // Fill opacity (0-1)
```

### Editable Layers

[](#editable-layers)

Make markers and shapes editable directly on the map by enabling the draw control:

```
class MyMapWidget extends MapWidget
{
    protected bool $hasEditLayersControl = true;

    protected function getMarkers(): array
    {
        return [
            Marker::make(-23.5505, -46.6333)
                ->title('Editable Marker')
                ->editable(),  // Make this marker editable

            Circle::make(-23.5505, -46.6333)
                ->radiusInKilometers(5)
                ->editable(),  // Make this circle editable
        ];
    }
}
```

You can also make all layers in a group editable:

```
LayerGroup::make([
    Marker::make(-23.5505, -46.6333)->title('Point 1'),
    Marker::make(-23.5515, -46.6343)->title('Point 2'),
    Marker::make(-23.5525, -46.6353)->title('Point 3'),
])
->name('Editable Points')
->editable(),  // All markers in the group are now editable
```

User Interactions
-----------------

[](#user-interactions)

### Popups and Tooltips

[](#popups-and-tooltips)

#### Tooltips (appear on hover)

[](#tooltips-appear-on-hover)

```
Marker::make(-23.5505, -46.6333)
    ->tooltip(
        content: 'São Paulo City',
        permanent: false,
        direction: 'top',
        options: ['offset' => [0, -20]]
    );

// Or using individual methods
Marker::make(-23.5505, -46.6333)
    ->tooltipContent('São Paulo')
    ->tooltipPermanent(true)
    ->tooltipDirection('top');
```

#### Popups (appear on click)

[](#popups-appear-on-click)

```
Marker::make(-23.5505, -46.6333)
    ->popupTitle('Store Location')
    ->popupContent('Visit our main store')
    ->popupFields([
        'address' => '123 Main Street',
        'phone' => '+55 11 1234-5678',
        'email' => 'contact@store.com',
    ])
    ->popupOptions(['maxWidth' => 300]);

// Or use shorthand
Marker::make(-23.5505, -46.6333)
    ->popup(
        content: 'Store description',
        fields: ['address' => '123 Main St', 'phone' => '+55 11 1234-5678'],
        options: ['maxWidth' => 300]
    );
```

**How popup fields work:** Keys are automatically converted to title case, underscores replaced with spaces, and translated using Laravel's `__()` helper. Both keys and values support translation keys.

#### Combined Usage

[](#combined-usage)

```
Marker::make(-23.5505, -46.6333)
    ->title('Pizza Palace')
    ->popupContent('Best pizza in town')
    ->popupFields([
        'address' => '123 Main St',
        'phone' => '+55 11 1234-5678',
        'rating' => '4.5 ⭐',
    ]);
```

### Click Actions

[](#click-actions)

#### Marker Click Handler

[](#marker-click-handler)

```
use Filament\Notifications\Notification;

Marker::make(-23.5505, -46.6333)
    ->title('Interactive Marker')
    ->action(function (Marker $marker) { // Or ->onClick()
        Notification::make()
            ->title('Marker Clicked!')
            ->body('ID: ' . $marker->getId())
            ->send();
    });
```

#### Shape Click Handler

[](#shape-click-handler)

```
Circle::make(-23.5505, -46.6333)
    ->radius(5000)
    ->action(function (Circle $circle) { // Or ->onClick()
        Notification::make()
            ->title('Circle clicked')
            ->send();
    });
```

#### From Model Records

[](#from-model-records)

```
protected function getMarkers(): array
{
    return Store::all()->map(function ($store) {
        return Marker::fromRecord($store)->action(function (Marker $marker, Store $record) { // Or ->onClick()
            Notification::make()
                ->title("You clicked: {$record->name}")
                ->body("Address: {$record->address}")
                ->send();

            return redirect()->route('stores.show', $record);
        });
    })->all();
}
```

#### Map Click Handler

[](#map-click-handler)

Handle clicks on the map itself:

```
public function handleMapClick(float $latitude, float $longitude): void
{
    Notification::make()
        ->title('Map clicked')
        ->body("Coordinates: {$latitude}, {$longitude}")
        ->send();
}
```

#### Field/Entry/Column Click Handlers

[](#fieldentrycolumn-click-handlers)

Handle map clicks in form fields, infolists, or table columns:

```
use EduardoRibeiroDev\FilamentLeaflet\Fields\MapPicker;
use Filament\Notifications\Notification;

MapPicker::make('location')
    ->height(300)
    ->onMapClick(function (float $latitude, float $longitude) {
        Notification::make()
            ->title('Location Selected')
            ->body("Lat: {$latitude}, Lng: {$longitude}")
            ->send();
    });
```

Handle layer (marker/shape) clicks:

```
use EduardoRibeiroDev\FilamentLeaflet\Layers\BaseLayer;

MapPicker::make('location')
    ->height(300)
    ->onLayerClick(function (BaseLayer $layer) {
        Notification::make()
            ->title('Layer Clicked')
            ->body("Layer ID: {$layer->getId()} - Type: {$layer->getType()}")
            ->send();
    });
```

Advanced Features
-----------------

[](#advanced-features)

### Model Integration &amp; CRUD Operations

[](#model-integration--crud-operations)

Enable creating markers directly from map clicks:

```
use App\Models\Location;

class LocationMapWidget extends MapWidget
{
    protected ?string $markerModel = Location::class;
    protected string $coordinatesColumnName = 'coordinates';

    protected function getFormComponents(): array
    {
        return [
            TextInput::make('name')->required(),
            ColorPicker::make('color')->rgb(),
            Textarea::make('description')->columnSpanFull(),
        ];
    }
}
```

When users click the map, a form modal opens to create a new marker. The widget automatically converts latitude/longitude into the configured coordinates column.

**Built-in Marker Actions:**

Define custom actions to execute when clicking markers with records using the `$markerClickAction` property:

```
use App\Models\Store;

class LocationMapWidget extends MapWidget
{
    protected ?string $markerModel = Store::class;
    protected string $coordinatesColumnName = 'coordinates';

    // Define the action to execute when a marker is clicked
    protected ?string $markerClickAction = 'view'; // 'view', 'edit', 'delete' or null

    protected function getMarkers(): array
    {
        return Store::all()->map(fn($store) =>
            Marker::fromRecord(
                record: $store,
                coordsColumn: 'coordinates',
                titleColumn: 'name',
            )
        )->all();
    }
}
```

**Available marker click actions:**

- `'view'` - Display a read-only modal with the marker's record details
- `'edit'` - Open an edit form for the marker's record (default)
- `'delete'` - Prompt to delete the marker's record
- `null` - No action

**Using a Resource Form:**

```
use App\Filament\Resources\Locations\LocationResource;

class LocationMapWidget extends MapWidget
{
    protected ?string $markerModel = Location::class;
    protected ?string $markerResource = LocationResource::class;
}
```

**Hooks:**

```
protected function afterMarkerCreated(Model $record): void
{
    Notification::make()
        ->title('Location created!')
        ->body("Created: {$record->name}")
        ->success()
        ->send();
}

protected function mutateFormDataBeforeCreate(array $data): array
{
    $data['user_id'] = auth()->id();
    $data['status'] = 'active';
    return parent::mutateFormDataBeforeCreate($data);
}
```

**Keep Maps in Sync with Tables:**

```
use EduardoRibeiroDev\FilamentLeaflet\Concerns\InteractsWithMap;

class ManageLocations extends ManageRecords
{
    use InteractsWithMap;
}
```

This automatically refreshes the map after create/edit/delete actions.

### GeoJSON Density Maps

[](#geojson-density-maps)

Display choropleth maps with custom density data:

```
class BrazilDensityWidget extends MapWidget
{
    protected ?string $geoJsonUrl = 'https://example.com/brazil-states.json';

    protected array $geoJsonColors = [
        '#FED976', '#FEB24C', '#FD8D3C', '#FC4E2A',
        '#E31A1C', '#BD0026', '#800026',
    ];

    protected function getGeoJsonData(): array
    {
        return [
            'SP' => 166.23,  // São Paulo
            'RJ' => 365.23,  // Rio de Janeiro
            'MG' => 33.41,   // Minas Gerais
        ];
    }

    protected function getGeoJsonTooltip(): string
    {
        return location->lat;  // Access latitude
echo $store1->location->lng;  // Access longitude

$distance = $store1->location->distanceTo($store2->location); // Calculate distance in kilometers
$store1->toArray(); // ['lat' => -23.5505, 'lng' => -46.6333]
$store1->toFlatArray(); // [-23.5505, -46.6333]

$store1->location = new Coordinate(-23.5505, -46.6333); // Update location
$store1->save();
```

**Methods:**

MethodDescription`__construct($lat, $lng)`Create a new Coordinate instance`toArray()`Convert to associative array with 'lat' and 'lng' keys`toFlatArray()`Convert to flat array \[$lat, $lng\]`fromArray($array)`Create from array with 'lat'/'lng' or numeric keys`fromObject($object)`Create from object with lat/lng properties`from($coordinates)`Universal factory method for arrays, objects, or Coordinate instances`distanceTo($other)`Calculate distance to another Coordinate (in kilometers)`castUsing()`Internal method for configuring Eloquent casting### GeoSearchResult

[](#geosearchresult)

The `GeoSearchResult` value object represents a geocoding search result with complete location information from geocoding providers.

**Properties:**

```
$result->coordinate;   // Coordinate object with lat/lng
$result->name;         // Short place name (e.g., "São Paulo")
$result->displayName;  // Full formatted address
$result->type;         // Location type (building, street, city, etc.)
$result->addresstype;  // Address classification
$result->address;      // Address value object with detailed components
$result->boundingbox;  // Geographic bounds [minLat, minLng, maxLat, maxLng]
```

### Address

[](#address)

The `Address` value object contains structured address information from geocoding results.

**Properties:**

PropertyTypeDescription`suburb`string|nullSuburb or neighborhood name`cityDistrict`string|nullCity district`city`string|nullCity name (town, village)`county`string|nullCounty name`state`string|nullState or province`province`string|nullProvince name`region`string|nullRegion name`postcode`string|nullPostal code`country`string|nullCountry name`countryCode`string|nullISO 3166-1 country codeConcern Methods Reference
-------------------------

[](#concern-methods-reference)

### HasGeoJsonFile

[](#hasgeojsonfile)

MethodDescription`getGeoJsonFileAttributeName()`Returns the model attribute storing GeoJSON (default: 'geojson')`getGeoJsonFileDisk()`Returns the storage disk for the file (default: null = local)`getExpirationTime()`Returns DateTime for temporary URL expiration (default: null = permanent)`getGeoJsonUrl()`Returns the accessible URL for the GeoJSON file### Map Configuration Properties

[](#map-configuration-properties)

These properties control core map behavior:

PropertyTypeDefaultDescription`$mapCenter`arraynullInitial map center \[latitude, longitude\] (null uses config default)`$autoCenter`boolfalseAuto-center to user's current location on load`$defaultZoom`int4Initial zoom level`$mapHeight`int598Map height in pixels`$mapDraggable`booltrueAllow users to pan by dragging`$mapZoomable`booltrueAllow users to zoom (scroll wheel, pinch)`$recenterMapTimeout`?intnullAuto-recenter after X milliseconds of panning`$maxZoom`int19Maximum zoom level allowed`$minZoom`int2Minimum zoom level allowed`$hasDrawMarkerControl`boolfalseShow draw marker control`$hasDrawCircleMarkerControl`boolfalseShow draw circle marker toolbar`$hasDrawCircleControl`boolfalseShow draw circle toolbar`$hasDrawPolylineControl`boolfalseShow draw polyline toolbar`$hasDrawRectangleControl`boolfalseShow draw rectangle toolbar`$hasDrawPolygonControl`boolfalseShow draw polygon toolbar`$hasDrawTextControl`boolfalseShow draw text toolbar`$hasEditLayersControl`boolfalseShow edit layers toolbar`$hasDragLayersControl`boolfalseShow drag layers toolbar`$hasRemoveLayersControl`boolfalseShow remove layers toolbar`$hasRotateLayersControl`boolfalseShow rotate layers toolbar`$hasCutPolygonControl`boolfalseShow cut polygon toolbar`$hasFullscreenControl`boolfalseShow fullscreen button`$hasSearchControl`boolfalseShow address search`$hasScaleControl`boolfalseShow distance scale`$hasZoomControl`booltrueShow zoom +/- buttons`$hasAttributionControl`boolfalseShow attribution text`$tileLayersUrl`mixedOpenStreetMapBase map tile layersLicense
-------

[](#license)

This package is open-sourced software licensed under the MIT license.

Credits
-------

[](#credits)

- Built for [Filament](https://filamentphp.com)
- Uses [Leaflet](https://leafletjs.com) for mapping
- Created by [Eduardo Ribeiro](https://github.com/eduardoribeirodev)

Support
-------

[](#support)

For issues, questions, or contributions, please visit the [GitHub repository](https://github.com/eduardoribeirodev/filament-leaflet). Don't forget, Jesus loves you ❤️.

###  Health Score

55

—

FairBetter than 97% of packages

Maintenance96

Actively maintained with recent releases

Popularity40

Moderate usage in the ecosystem

Community18

Small or concentrated contributor base

Maturity54

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 89.2% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~7 days

Recently: every ~14 days

Total

28

Last Release

18d ago

Major Versions

v1.1.0 → v2.0.02025-12-13

v2.1.0 → v3.0.02025-12-17

v3.1.1 → v4.0.02026-02-03

v4.7.6 → v5.0.02026-05-10

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/184874831?v=4)[Eduardo Ribeiro](/maintainers/eduardoribeirodev)[@eduardoribeirodev](https://github.com/eduardoribeirodev)

---

Top Contributors

[![eduardoribeirodev](https://avatars.githubusercontent.com/u/184874831?v=4)](https://github.com/eduardoribeirodev "eduardoribeirodev (58 commits)")[![akiraaisha](https://avatars.githubusercontent.com/u/6212018?v=4)](https://github.com/akiraaisha "akiraaisha (2 commits)")[![iulit](https://avatars.githubusercontent.com/u/18363695?v=4)](https://github.com/iulit "iulit (2 commits)")[![dotmot](https://avatars.githubusercontent.com/u/134087665?v=4)](https://github.com/dotmot "dotmot (1 commits)")[![firlus](https://avatars.githubusercontent.com/u/20861553?v=4)](https://github.com/firlus "firlus (1 commits)")[![rajabilal555](https://avatars.githubusercontent.com/u/15360941?v=4)](https://github.com/rajabilal555 "rajabilal555 (1 commits)")

### Embed Badge

![Health badge](/badges/eduardoribeirodev-filament-leaflet/health.svg)

```
[![Health](https://phpackages.com/badges/eduardoribeirodev-filament-leaflet/health.svg)](https://phpackages.com/packages/eduardoribeirodev-filament-leaflet)
```

###  Alternatives

[ysfkaya/filament-phone-input

A phone input component for Laravel Filament

3161.3M25](/packages/ysfkaya-filament-phone-input)[stephenjude/filament-feature-flags

Filament implementation of feature flags and segmentation with Laravel Pennant.

122177.8k1](/packages/stephenjude-filament-feature-flags)[marcelweidum/filament-expiration-notice

Customize the livewire expiration notice

94135.4k5](/packages/marcelweidum-filament-expiration-notice)[stephenjude/filament-blog

Filament Blog Builder

20619.4k](/packages/stephenjude-filament-blog)[crumbls/layup

A visual page builder plugin for Filament 5 — Divi-style grid layouts with extensible widgets.

592.7k1](/packages/crumbls-layup)[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3914.6k](/packages/rawilk-profile-filament-plugin)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
