Installation

Docs / 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:

terminal
composer require kwasii/livewire-mapcn

2. Publish Configuration & Assets

Publishing is optional. Publish the configuration file to customize default behaviour:

terminal
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':

terminal
php artisan vendor:publish --tag="livewire-mapcn-assets"

To customize the component markup, publish the views to resources/views/vendor/livewire-mapcn:

terminal
php artisan vendor:publish --tag="livewire-mapcn-views"
Published assets and views are copies. Re-publish them (with --force) after every package update so they stay in sync with the package.

3. Setup Layout

Include the styles and scripts in your root layout file (e.g., app.blade.php):

blade
<head>
    <!-- ... -->
    @livewireMapStyles
</head>
<body>
    <!-- ... -->
    @livewireScripts
    @livewireMapScripts
</body>
@livewireMapScripts loads MapLibre GL JS (v6 by default, which ships as an ES module) with a <script type="module"> and exposes it as window.maplibregl. Alpine.js comes with Livewire, so nothing else is needed.

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:

css
@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:

terminal
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:

KeyDefaultDescription
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:

php
// 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:

js
// 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: