Skip to main content
WireKit
Copy for LLM

Map

An interactive map for geo surfaces — fleet tracking, real-estate search, field-service dispatch, store locators. Like chart and the rich-text editor, map is an adapter: WireKit ships the themed chrome, the declarative API, the Alpine glue, and — most importantly — an accessible marker list that is always present. The heavy map engine and the map tiles are your app's concern, so the engine never enters WireKit's bundle — whichever of the two you pick, its weight is yours and not the component's.

map needs a peer dependency — a map engine loaded on the page. Pick one: MapLibre GL (the default — vector tiles, fully themeable) or Leaflet (lightweight raster tiles). See Choosing a Map Engine below, then the MapLibre GL setup guide. Without an engine the component degrades to the marker list plus a placeholder, so your data stays reachable.

Markers

Pass a center, a zoom, and an array of markers — each marker appears in the accessible list alongside the map. Selecting one (from the list or by clicking its pin on the map) pans the map, highlights the matching list entry, and emits marker-click. A marker's intent colors both its list dot and — once a map engine is loaded — the map pin itself, while the label and coordinates always carry the meaning, so the map never depends on color alone. An optional body line (an address, opening hours) renders under the label in the list, as the second line of the pin's tooltip, and inside the row's accessible name.

Both engines render standard on-canvas zoom controls (zoom in / out), so a reader can scale the map without a scroll-wheel gesture.

This overview stays engine-agnostic; the live previews live on the engine guides below, where a real map (with real tiles) renders. Pick an engine, then follow its guide.

Choosing a Map Engine

The same <x-wirekit::map> API drives either engine — you choose with the provider prop and supply the engine's library on the page. The marker list, the accessible API, and the theming are identical; only the tiles and the rendering differ.

Engine provider Tiles License Best for
MapLibre GL maplibre (default) Vector, fully styleable BSD-3-Clause Custom-styled, themeable interactive maps
Leaflet leaflet Raster (you pick the tile source) BSD-2-Clause A small footprint and any raster tile provider

Either engine is your app's dependency, not WireKit's — so load it only on the routes that render a map, never globally, or it weighs down every page. MapLibre GL in particular is the heavier of the two by a wide margin — check its current size against the engine's own documentation before you decide, because a figure repeated here would be a second copy of a number nothing in this repository measures. The MapLibre GL guide shows the route-scoped loading pattern.

Each engine has a dedicated guide: the MapLibre GL guide (install, styling, dark-mode tiles, real-world patterns) and the Leaflet & OpenStreetMap guide (install, raster tiles, the free OSM tile source with its attribution requirement, usage policy, and license — engine and tile source together on one page).

Engine vs. tile source — which page do I read? They are different layers, and a live map needs both. The engine is the JavaScript library that draws the map (MapLibre or Leaflet — that's the provider). The tile source is where the actual map imagery comes from (OpenStreetMap, a commercial vector style, your own server — that's the styleUrl). So Leaflet and OpenStreetMap are not alternatives to each other: Leaflet is one engine that can render OpenStreetMap tiles — which is why the Leaflet & OpenStreetMap guide covers both layers on one page: the engine setup first, then that tile source's attribution requirement, usage policy, and license.

Whichever engine you choose, the tiles carry their own license and attribution terms — they are separate from the engine's own (BSD) license. Always display the tile provider's required attribution, and check its usage policy before shipping at scale. The MapLibre GL guide covers this for each tile source.

Livewire & Realtime

Handle marker clicks server-side, and stream live positions in from Laravel Echo by calling the component's upsertMarker method:

{{-- 1. Open a detail panel when a marker is clicked --}}
<x-wirekit::map
    :center="$center"
    :markers="$this->vehicles"
    x-on:marker-click="$wire.selectVehicle($event.detail.id)"
/>
// 2. Shape markers for the map
public function getVehiclesProperty(): array
{
    return Vehicle::all()->map(fn ($v) => [
        'id' => $v->id,
        'lat' => $v->latitude,
        'lng' => $v->longitude,
        'label' => "{$v->name} — {$v->status}",
        'intent' => match ($v->status) {
            'active' => 'success', 'delayed' => 'warning', default => 'danger',
        },
    ])->all();
}
// 3. Push live position updates (optimistic; the list + map both update)
Echo.private('fleet').listen('VehicleMoved', (e) => {
    window.dispatchEvent(new CustomEvent('vehicle-moved', { detail: e }));
});
// Wire it on the element: x-on:vehicle-moved.window="upsertMarker($event.detail)"

Props

Prop Type Default Description
center array [0, 0] [lat, lng] initial center
zoom int 2 Initial zoom level
markers array [] [{id, lat, lng, label, body?, image?, tooltip?, intent?}] — the pin bubble follows the data shape: label alone is a text-only line, body adds a muted detail row (address, opening hours; also shown in the list), image adds a photo card above the text, and tooltip: 'image' makes the bubble photo-only (the label still names the pin for screen readers and the list)
provider string 'maplibre' maplibre · leaflet (peer dependency)
styleUrl string|null null Tile / style URL (provider-specific)
attribution string|null null Tile attribution shown in Leaflet's attribution control (e.g. © OpenStreetMap contributors) — required by some tile sources
height string '24rem' Map canvas height (CSS length)
ariaLabel string 'Map' Accessible name for the map region
reducedData string 'respect' respect · ignore. On respect, a browser reporting prefers-reduced-data: reduce gets the marker list and a Load the map anyway control instead of tiles — tiles are the largest network cost this library can cause, and the only one it controls at runtime. Use ignore where the canvas is the content rather than an illustration of it
listLabel string|null null Heading above the marker list (falls back to 'Locations'), and the switch that makes that list a screen-reader landmark — see Accessibility
highlight string 'ring' Selected-row highlight: ring (inset frame) · fill (tinted tile background)
highlightColor string 'accent' Highlight color: accent · success · warning · danger · neutral
list bool true Show the marker-list sidebar; false renders a map-only surface (the list stays sr-only for accessibility)
scope string|null null Scoped personalization name

Accessibility

The marker list is the screen-reader experience — always keep it visible (or at least in the DOM). The visual map is the enhancement on top.

  • A map is opaque to assistive tech, so the marker list is mandatory and always rendered. Each entry is a focusable button labeled with the marker name and its coordinates, so the data is reachable without seeing the map.
  • The map canvas carries role="application" with an aria-label and is keyboard-focusable; the marker list is a keyboard-reachable scroll region (WCAG 2.1.1) whenever it is visible.
  • The list becomes a screen-reader landmark only when you set listLabel. It is then a role="region" under that name. Without one it stays a plain focusable scroller — the old fallback made every map on a store-locator page the same landmark, "Locations", which axe reports as landmark-unique. The visible heading above the list keeps that default either way.
  • With list="false" the list collapses to its sr-only companion, which does not scroll; it drops out of the tab order (tabindex="-1") rather than becoming a focus stop on something nobody can see (WCAG 2.4.7). Its buttons stay reachable, which is what keeps the screen-reader path intact.
  • Marker status is conveyed by the label text, never the dot color alone.
  • Pan/fly animations honor prefers-reduced-motion (the map jumps instead).

Keyboard Interaction

Key Action
Tab Move into the map canvas and through the marker list
Enter / Space Select a marker (pans the map, emits marker-click)

Design Tokens

Element Token
Canvas backdrop --color-wk-bg-muted
List surface --color-wk-bg-elevated
Marker dot (accent/success/warning/danger) --color-wk-accent / --color-wk-success / --color-wk-warning / --color-wk-danger
Borders --color-wk-border
Focus ring --color-wk-ring

Customization

Set the default provider and zoom via config/wirekit.php:

'components' => [
    'map' => [
        'provider' => 'leaflet',
        'zoom' => 11,
    ],
],

Further Reading

Was this page helpful?

Thank you for your feedback!

Voting requires cookies or local storage. What we store