@locationlabuo/leaflet-sveltified
v0.6.3
Published
Svelte Wrapper for Leaflet
Maintainers
Readme
Leaflet Sveltified
A declarative Svelte 5 wrapper for Leaflet, providing a component-based API for building interactive maps.
Features
- 🗺️ Full Leaflet Integration - All major Leaflet features available as Svelte components
- ⚡ Svelte 5 Runes - Built with modern Svelte 5 runes (
$state,$effect,$props) - 🔄 Reactive by Default - Props automatically sync with Leaflet objects
- 📦 TypeScript Support - Full type definitions for all components
- 🎨 Declarative API - Compose maps using familiar Svelte component syntax
- 🧩 Plugin Support - Includes MarkerCluster plugin support
- 🧹 Automatic Cleanup - Proper memory management and event cleanup
Installation
npm install @locationlabuo/leaflet-sveltified leafletNote: This library requires Svelte 5. Make sure you're using svelte@^5.0.0.
Quick Start
<script>
import { LeafletMap, TileLayer, Marker, Popup } from '@locationlabuo/leaflet-sveltified';
</script>
<LeafletMap options={{ center: [51.505, -0.09], zoom: 13 }}>
<TileLayer url="https://tile.openstreetmap.org/{z}/{x}/{y}.png" />
<Marker latlng={[51.505, -0.09]}>
<Popup>
<h2>Hello World!</h2>
<p>This is a popup.</p>
</Popup>
</Marker>
</LeafletMap>Basic Usage
Map Component
The LeafletMap component is the root container for all map features.
<script>
import { LeafletMap } from '@locationlabuo/leaflet-sveltified';
import type { MapOptions } from 'leaflet';
let mapOptions: MapOptions = $state({
center: [51.505, -0.09],
zoom: 13,
maxZoom: 19
});
</script>
<LeafletMap {options} />Tile Layers
Add tile layers to display map imagery:
<script>
import { LeafletMap, TileLayer } from '@locationlabuo/leaflet-sveltified';
</script>
<LeafletMap options={{ center: [0, 0], zoom: 3 }}>
<TileLayer url="https://tile.openstreetmap.org/{z}/{x}/{y}.png" />
</LeafletMap>Markers
Add markers to the map:
<script>
import { LeafletMap, TileLayer, Marker } from '@locationlabuo/leaflet-sveltified';
let position = $state([51.505, -0.09]);
let draggable = $state(false);
</script>
<LeafletMap options={{ center: position, zoom: 13 }}>
<TileLayer url="https://tile.openstreetmap.org/{z}/{x}/{y}.png" />
<Marker
latlng={position}
options={{ draggable }}
events={{
dragend: (e) => {
position = [e.target.getLatLng().lat, e.target.getLatLng().lng];
}
}}
/>
</LeafletMap>Custom Icons
Use the Icon snippet to customize marker icons:
<script>
import { LeafletMap, TileLayer, Marker, Icon } from '@locationlabuo/leaflet-sveltified';
let color = $state('green');
</script>
<LeafletMap options={{ center: [0, 0], zoom: 3 }}>
<TileLayer url="https://tile.openstreetmap.org/{z}/{x}/{y}.png" />
<Marker latlng={[10, 10]}>
{#snippet icon()}
<Icon
options={{
iconUrl: `https://leafletjs.com/examples/custom-icons/leaf-${color}.png`,
shadowUrl: 'https://leafletjs.com/examples/custom-icons/leaf-shadow.png',
iconSize: [38, 95],
shadowSize: [50, 64],
iconAnchor: [22, 94],
shadowAnchor: [4, 62],
popupAnchor: [-3, -76]
}}
/>
{/snippet}
</Marker>
</LeafletMap>Popups and Tooltips
Add interactive popups and tooltips:
<script>
import { LeafletMap, TileLayer, Marker, Popup, Tooltip } from '@locationlabuo/leaflet-sveltified';
let popupOpen = $state(false);
</script>
<LeafletMap options={{ center: [0, 0], zoom: 3 }}>
<TileLayer url="https://tile.openstreetmap.org/{z}/{x}/{y}.png" />
<Marker latlng={[10, 10]}>
<Popup bind:open={popupOpen}>
<h2>Bound Popup</h2>
<p>This popup's open state is bound to a variable.</p>
</Popup>
<Tooltip>Hover tooltip</Tooltip>
</Marker>
</LeafletMap>Vector Layers
Add polygons, polylines, circles, and rectangles:
<script>
import {
LeafletMap,
TileLayer,
Polygon,
Polyline,
Circle,
Rectangle
} from '@locationlabuo/leaflet-sveltified';
</script>
<LeafletMap options={{ center: [0, 0], zoom: 3 }}>
<TileLayer url="https://tile.openstreetmap.org/{z}/{x}/{y}.png" />
<Polygon
latlngs={[
[0, 0],
[10, 0],
[10, 10],
[0, 10]
]}
options={{ color: 'blue', fillColor: 'lightblue' }}
/>
<Polyline
latlngs={[
[-10, -10],
[0, 0],
[10, 10]
]}
options={{ color: 'red' }}
/>
<Circle latlng={[20, 20]} options={{ radius: 50000, color: 'green' }} />
<Rectangle
bounds={[
[30, 30],
[40, 40]
]}
options={{ color: 'purple' }}
/>
</LeafletMap>Layer Groups
Organize layers into groups:
<script>
import { LeafletMap, TileLayer, LayerGroup, Marker } from '@locationlabuo/leaflet-sveltified';
</script>
<LeafletMap options={{ center: [0, 0], zoom: 3 }}>
<TileLayer url="https://tile.openstreetmap.org/{z}/{x}/{y}.png" />
<LayerGroup>
<Marker latlng={[10, 10]} />
<Marker latlng={[20, 20]} />
<Marker latlng={[30, 30]} />
</LayerGroup>
</LeafletMap>GeoJSON
Display GeoJSON data:
<script>
import { LeafletMap, TileLayer, GeoJSON } from '@locationlabuo/leaflet-sveltified';
const geojsonData = {
type: 'FeatureCollection',
features: [
{
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [0, 0]
},
properties: {
name: 'Point 1'
}
}
]
};
</script>
<LeafletMap options={{ center: [0, 0], zoom: 3 }}>
<TileLayer url="https://tile.openstreetmap.org/{z}/{x}/{y}.png" />
<GeoJSON data={geojsonData} />
</LeafletMap>Event Handling
All components support event handlers through the events prop:
<script>
import { LeafletMap, TileLayer, Marker } from '@locationlabuo/leaflet-sveltified';
import type { LeafletMouseEventHandlerFn } from 'leaflet';
const handleClick: LeafletMouseEventHandlerFn = (e) => {
console.log('Marker clicked at:', e.latlng);
};
</script>
<LeafletMap
options={{ center: [0, 0], zoom: 3 }}
events={{
click: (e) => console.log('Map clicked:', e.latlng)
}}
>
<TileLayer url="https://tile.openstreetmap.org/{z}/{x}/{y}.png" />
<Marker
latlng={[10, 10]}
events={{
click: handleClick,
dragend: (e) => console.log('Marker dragged')
}}
/>
</LeafletMap>Marker Clustering
Use the MarkerCluster plugin for clustering markers:
<script>
import { LeafletMap, TileLayer } from '@locationlabuo/leaflet-sveltified';
import { MarkerCluster } from '@locationlabuo/leaflet-sveltified/plugins';
import Marker from '@locationlabuo/leaflet-sveltified';
</script>
<LeafletMap options={{ center: [0, 0], zoom: 3 }}>
<TileLayer url="https://tile.openstreetmap.org/{z}/{x}/{y}.png" />
<MarkerCluster>
<Marker latlng={[10, 10]} />
<Marker latlng={[10.1, 10.1]} />
<Marker latlng={[10.2, 10.2]} />
</MarkerCluster>
</LeafletMap>Component API
LeafletMap
The root map component.
Props:
options: MapOptions(required) - Leaflet map optionsevents?: LeafletEventHandlerFnMap- Map event handlersgetMap?: () => Map | undefined- Bindable function to get the underlying Leaflet Map instancechildren?: Snippet- Child components (layers, controls, etc.)
Layer Components
All layer components share common props:
options?: LayerOptions- Leaflet layer optionsevents?: EventHandlers- Event handlers specific to the layer typechildren?: Snippet- Child components (popups, tooltips, etc.)
Available Layer Components:
TileLayer- Raster tile layersMarker- Point markersPolygon- Polygon shapesPolyline- Polyline shapesCircle- Circle shapesCircleMarker- Circle markers (fixed pixel size)Rectangle- Rectangle shapesGeoJSON- GeoJSON data layersLayerGroup- Groups of layersFeatureGroup- Feature groups with event handling
UI Components
Popup- Popup overlaysopen?: boolean(bindable) - Control popup visibilityoptions?: PopupOptions- Popup optionsevents?: PopupEventHandlers- Event handlerschildren?: Snippet- Popup content
Tooltip- Tooltip overlaysopen?: boolean(bindable) - Control tooltip visibilityoptions?: TooltipOptions- Tooltip optionsevents?: TooltipEventHandlers- Event handlerschildren?: Snippet- Tooltip content
DivOverlay- Custom div overlaysopen?: boolean(bindable) - Control overlay visibilitylatlng?: LatLngExpression- Overlay positionoptions?: DivOverlayOptions- Overlay optionsevents?: DivOverlayEventHandlers- Event handlerschildren?: Snippet- Overlay content
Icon- Custom marker icons (used as snippet)options: IconOptions(required) - Icon options
DivIcon- HTML div icons (used as snippet)options?: DivIconOptions- DivIcon optionschildren?: Snippet- Icon content
Control Components
ZoomControl- Zoom controlScaleControl- Scale controlAttributionControl- Attribution controlControl- Custom controls
All control components accept:
options?: ControlOptions- Control optionsevents?: ControlEventHandlers- Event handlers
Advanced Usage
Accessing Leaflet Instances
Use context functions to access underlying Leaflet objects:
<script>
import { getMapContext, getMarkerContext } from '@locationlabuo/leaflet-sveltified';
const mapContext = getMapContext();
const markerContext = getMarkerContext();
// Access the Leaflet Map instance
const map = mapContext?.map;
// Access the Leaflet Marker instance
const marker = markerContext?.marker;
</script>Reactive Updates
All props are reactive. Changes to props automatically update the Leaflet objects:
<script>
let position = $state([51.505, -0.09]);
let opacity = $state(1.0);
</script>
<Marker latlng={position} options={{ opacity }} />
<!--
When position or opacity change, the marker automatically updates
-->Conditional Rendering
Components handle mounting/unmounting automatically:
<script>
let showMarker = $state(true);
</script>
{#if showMarker}
<Marker latlng={[10, 10]} />
{/if}
<!-- Marker is properly removed from map when showMarker becomes false -->TypeScript Support
This library is written in TypeScript and provides full type definitions. All component props are typed using Leaflet's type definitions.
import type { MapOptions, LatLngExpression } from 'leaflet';
import { LeafletMap, Marker } from '@locationlabuo/leaflet-sveltified';
const options: MapOptions = {
center: [51.505, -0.09],
zoom: 13
};
const position: LatLngExpression = [51.505, -0.09];Development
This library is built with:
- Svelte 5
- SvelteKit
- TypeScript
- Leaflet
Running the Development Server
npm install
npm run devBuilding
npm run buildPackage the Library
npm run packageContributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT
Repository
Acknowledgments
Built by the Location Innovation Lab at the University of Oregon.
