Leaflet.js Offline — Building Maps Without Internet
In this tutorial, you will learn about Leaflet.js Offline. We cover key concepts, practical examples, and best practices to help you master this topic.
Leaflet.js offline maps allow users to view previously cached map tiles and data when disconnected from the internet, using service workers and local storage.
What You'll Learn
By the end of this guide, you will cache map tiles with a service worker, use libraries like Leaflet.Offline for tile management, pre-download tiles for a bounding box, detect online/offline status, and build an offline-first map app.
Service Worker Caching
// sw.js
self.addEventListener('fetch', function(event) {
if (event.request.url.includes('tile.openstreetmap.org')) {
event.respondWith(
caches.match(event.request)
.then(function(cached) {
return cached || fetch(event.request).then(function(response) {
var clone = response.clone();
caches.open('tiles-v1').then(function(cache) {
cache.put(event.request, clone);
});
return response;
});
})
);
}
});
Detecting Connectivity
window.addEventListener('online', function() {
map._tileLayers._layers[0]._update();
document.getElementById('status').textContent = 'Online';
});
window.addEventListener('offline', function() {
document.getElementById('status').textContent = 'Offline mode';
});
Pre-Downloading Tiles
var bounds = [
[40.7, -74.02],
[40.8, -73.98]
];
var minZoom = 10;
var maxZoom = 15;
var tileUrl = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
for (var z = minZoom; z <= maxZoom; z++) {
var tileBounds = L.bounds(
map.project(bounds[0], z),
map.project(bounds[1], z)
);
for (var x = tileBounds.min.x; x <= tileBounds.max.x; x++) {
for (var y = tileBounds.min.y; y <= tileBounds.max.y; y++) {
var url = tileUrl.replace('{z}', z).replace('{x}', x).replace('{y}', y);
fetch(url); // Triggers SW caching
}
}
}
Common Mistakes
1. CORS Issues with Tile Cache
Some tile servers block CORS. Use a proxy or configure the tile server to allow caching.
2. Storage Limits
Tile caches grow quickly (a few MB per zoom level). Set a cache size limit and purge old tiles.
3. No Fallback for Uncached Tiles
When offline and a tile is missing, show a placeholder image. Do not show broken image icons.
4. Stale Tiles Not Updated
Service workers serve cached tiles indefinitely. Implement a versioning Strategy to refresh tiles.
5. GeoJSON Data Not Cached
Only tiles are cached by default. Cache API responses and GeoJSON files separately.
Practice Questions
Q1: What service worker event handles tile caching? A: The 'fetch' event intercepts tile requests and serves from cache or network.
Q2: How do you know if the user is offline? A: Listen for 'online' and 'offline' events on the window object.
Q3: What is the storage limit for a service worker cache? A: Typically 50-100MB depending on the browser. Use the Storage API to check.
Q4: How do you pre-cache tiles for a specific region? A: Iterate over the bounding box at each zoom level and fetch each tile URL.
Q5: How do you clear the tile cache? A: Use caches.open('tiles-v1').then(function(cache) { cache.keys().then(/* delete */); });
Challenge: Build an offline map app that lets users select a bounding box on the map and click "Download for Offline." Show download progress and total tiles count.
FAQ
Try It Yourself
Build an offline-aware map.
<!DOCTYPE html>
<html>
<head>
<title>Offline Map Demo</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet@1.9/dist/leaflet.js"></script>
</head>
<body style="font-family:sans-serif;padding:20px;">
<h2>Offline Map</h2>
<div id="status" style="padding:6px 12px;background:#4ecdc4;color:white;border-radius:4px;margin-bottom:8px;display:inline-block;">Online</div>
<div id="map" style="height:400px;border-radius:8px;"></div>
<script>
var map = L.map('map').setView([40.7128, -74.0060], 12);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© OSM'
}).addTo(map);
var statusDiv = document.getElementById('status');
function updateStatus() {
if (navigator.onLine) {
statusDiv.textContent = 'Online';
statusDiv.style.background = '#4ecdc4';
} else {
statusDiv.textContent = 'Offline (cached tiles only)';
statusDiv.style.background = '#ff6b35';
}
}
window.addEventListener('online', updateStatus);
window.addEventListener('offline', updateStatus);
updateStatus();
// Register service worker for tile caching
if ('serviceWorker' in navigator) {
// In production, register sw.js here
console.log('Service Worker supported');
}
</script>
</body>
</html>
What's Next
Optimize map performance.
Performance — Performance optimization. Animations — Map animations.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro