Installation
composer require esadewater/livewire-maps
Publish the config file (if needed):
php artisan vendor:publish --provider="Esadewater\LivewireMaps\LivewireMapsServiceProvider"
Basic Usage Register the component in your Livewire class:
use Esadewater\LivewireMaps\LivewireMaps;
public function mount()
{
$this->mapOptions = [
'center' => [40.416775, -3.703790], // Madrid coordinates
'zoom' => 12,
];
}
public function render()
{
return view('livewire.your-component')->layout('layouts.app');
}
First Blade View
<livewire-maps wire:model="mapOptions" />
Ensure you include the required JS/CSS in your layout:
@livewireScripts
@livewireStyles
public $markers = [
['lat' => 40.416775, 'lng' => -3.703790, 'title' => 'Madrid'],
];
<livewire-maps
wire:model="mapOptions"
wire:model.defer="markers"
marker-options='{"icon": {"iconUrl": "/path/to/icon.png"}}'
/>
Dynamic Marker Management
public function addMarker($lat, $lng, $title)
{
$this->markers[] = compact('lat', 'lng', 'title');
}
public function removeMarker($index)
{
unset($this->markers[$index]);
}
Interactive Features
map-clicked event:
<livewire-maps
wire:map-clicked="handleMapClick"
wire:model="mapOptions"
/>
public function handleMapClick($event)
{
$this->addMarker($event['lat'], $event['lng'], 'New Point');
}
public $markerOptions = [
'draggable' => true,
'dragend' => 'updateMarkerPosition',
];
public function updateMarkerPosition($event)
{
$index = $event['markerId'];
$this->markers[$index]['lat'] = $event['lat'];
$this->markers[$index]['lng'] = $event['lng'];
}
Integration with Laravel Backend
public function saveMarkers()
{
foreach ($this->markers as $marker) {
Marker::updateOrCreate(
['id' => $marker['id'] ?? null],
$marker
);
}
}
public function mount()
{
$this->markers = Marker::all()->toArray();
}
Custom Map Layers
layer-options to add tiles or overlays:
<livewire-maps
wire:model="mapOptions"
layer-options='{
"tiles": [{
"url": "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
"attribution": "© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>"
}]
}'
/>
Geocoding Integration
public function handleMapClick($event)
{
$address = $this->geocode($event['lat'], $event['lng']);
$this->addMarker($event['lat'], $event['lng'], $address);
}
Use a service like Nominatim or a paid API (e.g., Google Maps).Performance Optimization
defer or debounce for marker updates:
wire:model.defer="markers"
public function loadMoreMarkers()
{
$this->markers = Marker::offset($this->offset)->limit(50)->get()->toArray();
$this->offset += 50;
}
Missing Dependencies
// resources/js/app.js
import 'leaflet/dist/leaflet.css';
import 'leaflet';
Coordinate Format
[lat, lng], not [lng, lat] (common in Google Maps).console.log in the browser to verify coordinates:
<script>
window.addEventListener('livewire:init', () => {
Livewire.on('map-ready', (map) => {
console.log('Map center:', map.getCenter());
});
});
</script>
Livewire Property Binding
wire:model is used for mutable options (e.g., center, zoom).wire:init or wire:ignore for static configs:
<livewire-maps
wire:init="initMap"
wire:ignore="staticOptions"
/>
Marker ID Conflicts
markerId is unique (e.g., use database IDs or UUIDs).Console Logs
<script>
Livewire.on('map-event', (event) => {
console.log('Event:', event);
});
</script>
$this->dispatch('map-event', data: ['type' => 'custom', 'data' => $event]);
Inspecting the Map Object
<script>
Livewire.on('map-ready', (map) => {
console.log('Full map object:', map);
});
</script>
document.addEventListener('livewire:init', () => {
Livewire.hook('element.updated', (el) => {
if (el.tagName === 'LIVEWIRE-MAPS') {
const map = el._x_dataStack[0].map;
console.log('Map instance:', map);
}
});
});
Common Errors
wire:ignore or x-data to delay rendering.{{ dd($this->markers) }} in a blade template to debug.Custom Directives
<livewire-maps x-data="{ customData: null }" />
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('mapExtender', () => ({
init() {
Livewire.on('map-ready', (map) => {
this.customData = map;
});
}
}));
});
</script>
Leaflet Plugin Integration
<script src="https://unpkg.com/leaflet-control-geocoder@2.0.0/dist/Control.Geocoder.js"></script>
<livewire-maps wire:model="mapOptions" />
<script>
Livewire.on('map-ready', (map) => {
L.control.geocoder().addTo(map);
});
</script>
Server-Side Processing
How can I help you explore Laravel packages today?