Installation
Requirements
- PHP: 8.3 or higher
- Laravel: 11, 12 or 13
- Livewire: 3 or 4
- Alpine.js: bundled with Livewire 3 & 4, nothing to install
Tailwind CSS is not required. The package stylesheet loaded by @livewireMapStyles styles every component, and MapLibre GL JS is loaded from a CDN for you.
1. Install via Composer
Install the package using Composer:
composer require kwasii/livewire-mapcn
2. Publish Configuration & Assets
Publishing is optional. Publish the configuration file to customize default behaviour:
php artisan vendor:publish --tag="livewire-mapcn-config"
The package JS and CSS are served from a package route by default, so you do not need to publish them. If you prefer serving static files, publish them and set inject_assets to 'published':
php artisan vendor:publish --tag="livewire-mapcn-assets"
To customize the component markup, publish the views to resources/views/vendor/livewire-mapcn:
php artisan vendor:publish --tag="livewire-mapcn-views"
3. Setup Layout
Include the styles and scripts in your root layout file (e.g., app.blade.php):
<head> <!-- ... --> @livewireMapStyles </head> <body> <!-- ... --> @livewireScripts @livewireMapScripts </body>
4. Styling (No Tailwind Required)
All components (controls, popups, tooltips, labels, route lists, loaders) are styled by the package stylesheet included with @livewireMapStyles. You do not need Tailwind CSS, and you do not need to add the package views to your Tailwind sources.
If you do use Tailwind, you can still pass utility classes through the class prop or use them in slot content (popups, tooltips, custom markers). Those classes live in your own views, so Tailwind picks them up as usual. Only add the package views as a source if you published and edited them to use Tailwind classes:
@source "../views/vendor/livewire-mapcn/**/*.blade.php";
5. AI Integration (Optional)
If you use AI coding agents, you can install the package's skills and guidelines using Laravel Boost:
php artisan boost:install
This command allows AI agents to understand the package's components, props, and best practices directly within your workspace.
Configuration
Customize the package behaviour via config/livewire-mapcn.php:
| Key | Default | Description |
|---|---|---|
| default_provider | 'carto-positron' | Default tile provider for all maps |
| dark_provider | 'carto-dark-matter' | Provider used for dark mode |
| follow_system_theme | false | With theme="auto", maps follow a dark/light class or data-theme attribute on <html>. Enable to also follow the OS preference when neither is present |
| default_height | 'full' | Default CSS height if not specified in prop |
| default_zoom | 7 | Default initial zoom level |
| default_center | [0, 0] | Default initial coordinates [lng, lat] |
| osrm_url | 'https://router.project-osrm.org' | Base URL for fetching road directions via OSRM |
| inject_assets | 'route' | 'route' serves the package JS/CSS from a package route; 'published' uses public/vendor/livewire-mapcn |
| load_from_cdn | true | Load MapLibre JS/CSS from a CDN. Set false if you bundle MapLibre yourself (assign it to window.maplibregl) |
| maplibre_version | '6.14.0' | MapLibre GL JS version loaded from jsDelivr when cdn_url / cdn_css_url are null |
| cdn_url | null | Exact MapLibre GL JS URL. Null derives it from maplibre_version. A URL ending in .mjs loads as an ES module, anything else as a classic (UMD) script |
| cdn_css_url | null | Exact MapLibre GL CSS URL. Null derives it from maplibre_version |
| carto_license | 'non-commercial' | Informational. CARTO basemaps are free for non-commercial use; commercial apps need a CARTO enterprise license (or another provider) |
| cluster_popup_view | null | Default Blade view for cluster point popups ({property} placeholders work) |
| custom_events | [] | Extra MapLibre event names to forward to Livewire on every map, dispatched as map:{event-name} |
MapLibre Version
MapLibre GL JS v6 (the default) is ESM-only. To stay on v5, pin its UMD build; any URL that does not end in .mjs is loaded as a classic script:
// config/livewire-mapcn.php 'maplibre_version' => '5.19.0', 'cdn_url' => 'https://cdn.jsdelivr.net/npm/maplibre-gl@5.19.0/dist/maplibre-gl.js',
To bundle MapLibre with Vite instead of using the CDN, set load_from_cdn to false, then expose the library globally and import its CSS:
// resources/js/app.js import * as maplibregl from 'maplibre-gl'; import 'maplibre-gl/dist/maplibre-gl.css'; window.maplibregl = maplibregl;
Upgrading from v1
Most apps upgrade with composer update kwasii/livewire-mapcn. Check the following:
- Published views: the component markup changed. If you published the views, re-publish them with php artisan vendor:publish --tag="livewire-mapcn-views" --force and re-apply your edits. Do the same for livewire-mapcn-assets if you use inject_assets => 'published'.
- Remove manual wire:ignore wrappers around maps. <x-map> now uses wire:ignore.self, so its children (markers, routes, layers) update reactively from Livewire state. Give items rendered in loops a wire:key.
- MapLibre v6: if you set cdn_url, set it back to null or to a .mjs URL, or pin maplibre_version to a v5 release (see above).
- Tailwind is no longer required. You can remove the package's @source line from your CSS.
- Events: Livewire listeners no longer receive map events twice, and every event payload now includes mapId.
- Routes: with-stops now draws dots only at the waypoints you pass, not at every coordinate of a fetched route.
- Marker popups & tooltips: <x-marker-popup> and <x-marker-tooltip> anchor now defaults to auto (MapLibre picks the side with the most room) with a 16px offset above the marker.
- Other defaults: cluster circles are slightly smaller (cluster-size-stops is now [[0, 18], [100, 26], [1000, 34]]), and height="full" now renders as 100%.
- Deprecated: max-features-to-inline on cluster layers (data is always embedded in a JSON script block) and map-id on <x-map-route-list> (the list finds its route by id anywhere on the page). Both are accepted but ignored.
Verify Installation
After installation, verify everything works by adding a simple map to any Blade view: