14 releases
Uses new Rust 2024
| 0.3.1 | Dec 16, 2025 |
|---|---|
| 0.3.0 | Dec 8, 2025 |
| 0.2.1 | Oct 18, 2025 |
| 0.1.8-rc.2 | Sep 30, 2025 |
| 0.1.8-rc.0 | Aug 21, 2025 |
#64 in Geospatial
180KB
3.5K
SLoC
Dioxus Leaflet
A general-purpose Leaflet map component for Dioxus applications. This crate provides an easy-to-use, reactive map component that integrates seamlessly with Dioxus applications.
Features
- Component-based map objects - intuitive Dioxus components for markers, polygons, and popups
- Interactive markers with popups and custom styling
- Reactive map components that auto-update when your data changes
- Flexible Leaflet integration - CDN with version selection or local files
- Configurable Leaflet resources with integrity checking for security
- Responsive design with customizable dimensions
- Customizable tile layers including OpenStreetMap and satellite imagery
- Configurable map options for zoom, dragging, and interaction controls
- Event handling for map clicks and movements
Screenshots


Also works on mobile !


Installation
Add this to your Cargo.toml:
[dependencies]
dioxus-leaflet = "0.3.0"
dioxus = "0.7.0-rc.2"
Quick Start
Here's a simple example to get you started:
use dioxus::prelude::*;
use dioxus_leaflet::{Map, MapPosition, Marker, Popup};
fn App() -> Element {
rsx! {
Map {
initial_position: MapPosition::new(51.505, -0.09, 5.0),
height: "500px",
width: "100%",
Marker {
coordinate: LatLng::new(51.505, -0.09),
Popup {
b { "London" }
br { }
"Capital of England"
}
}
Marker {
coordinate: LatLng::new(48.8566, 2.3522),
Popup {
b { "Paris" }
br { }
"Capital of France"
}
}
}
}
}
fn main() {
dioxus::launch(App);
}
Core Components
Map Component
The main Map component provides a full-featured Leaflet map. It can contain child components like Marker and Polygon:
rsx! {
Map {
initial_position: MapPosition::new(51.505, -0.09, 13.0),
height: "400px",
width: "100%",
class: "my-custom-map",
style: "border: 1px solid #ccc;",
on_click: move |pos| {
println!("Map clicked at: {}", pos);
},
// Add markers as child components
Marker {
coordinate: LatLng::new(51.505, -0.09),
// Add popup as child of marker
Popup {
b { "London" }
br {}
"Capital of England"
}
}
// Add polygons as child components
Polygon {
coordinates: vec![
LatLng::new(51.5, -0.1),
LatLng::new(51.5, 0.0),
LatLng::new(51.4, 0.0),
],
options: PathOptions {
color: Color::new([1., 0., 0.]),
fill: true,
..Default::default()
},
// Add popup to polygon too
Popup {
"A red triangle"
}
}
}
}
Map Properties
| Property | Type | Default | Description |
|---|---|---|---|
initial_position |
MapPosition |
London coordinates | Initial map center and zoom |
markers |
Vec<MapMarker> |
Empty | Markers to display on the map |
height |
String |
"500px" |
Height of the map container |
width |
String |
"100%" |
Width of the map container |
options |
MapOptions |
Default | Map configuration options |
class |
String |
"" |
Additional CSS classes |
style |
String |
"" |
Additional CSS styles |
on_marker_click |
EventHandler<MapMarker> |
None | Callback when marker is clicked |
on_map_click |
EventHandler<MapPosition> |
None | Callback when map is clicked |
on_map_move |
EventHandler<MapPosition> |
None | Callback when map is moved |
Leaflet Resources Configuration
Configure how Leaflet CSS and JavaScript files are loaded. You can use CDN with specific versions or provide local files.
Using CDN with Default Version (1.9.4)
// Default configuration uses Leaflet 1.9.4 from unpkg.com
let options = MapOptions::default();
Using CDN with Specific Version
use dioxus_leaflet::{MapOptions, LeafletResources};
let options = MapOptions::default()
.with_leaflet_resources(LeafletResources::cdn("1.9.3"));
Using Custom CDN Base URL
let options = MapOptions::default()
.with_leaflet_resources(
LeafletResources::cdn_with_base_url("1.9.4", "https://cdn.jsdelivr.net/npm")
);
Using Local Files
let options = MapOptions::default()
.with_leaflet_resources(LeafletResources::local(
"/static/css/leaflet.css",
"/static/js/leaflet.js"
));
Leaflet Resource Options
| Method | Description | Security |
|---|---|---|
LeafletResources::cdn(version) |
Uses unpkg.com CDN with specified version | Includes integrity checking for known versions |
LeafletResources::cdn_with_base_url(version, base_url) |
Uses custom CDN base URL | No integrity checking for custom URLs |
LeafletResources::local(css_path, js_path) |
Uses local files from specified paths | No integrity checking |
Note: Integrity checking is automatically applied for known Leaflet versions (1.9.2, 1.9.3, 1.9.4) when using the default unpkg.com CDN.
Working with Markers
Basic Markers
let marker = MapMarker::new(51.505, -0.09, "London");
Advanced Markers
let marker = MapMarker::new(51.505, -0.09, "London")
.with_description("The capital city of England")
.with_custom_data("country", "UK")
.with_custom_data("population", "8900000")
.with_popup_options(PopupOptions {
max_width: Some(250),
close_button: Some(true),
auto_close: Some(false),
..Default::default()
});
Custom Marker Icons
use dioxus_leaflet::MarkerIcon;
let custom_icon = MarkerIcon::new("https://example.com/custom-icon.png")
.with_size(32, 32)
.with_anchor(16, 32);
let marker = MapMarker::new(51.505, -0.09, "Custom Marker")
.with_icon(custom_icon);
Map Configuration
Map Options
Customize map behavior with MapOptions. All options have sensible defaults:
use dioxus_leaflet::{MapOptions, TileLayer};
// Full configuration with all options specified
let options = MapOptions {
zoom_control: true,
scroll_wheel_zoom: true,
double_click_zoom: false,
touch_zoom: true,
dragging: true,
keyboard: true,
attribution_control: true,
tile_layer: TileLayer::satellite(), // Use satellite imagery
};
// Minimal configuration using builder pattern
let minimal_options = MapOptions::default()
.with_double_click_zoom(false)
.with_tile_layer(TileLayer::satellite());
// All controls disabled
let disabled_options = MapOptions::minimal()
.with_tile_layer(TileLayer::satellite());
// Use default configuration
let default_options = MapOptions::default(); // All options set to sensible defaults
rsx! {
Map {
options: options,
// ... other props
}
}
Available Map Options
| Option | Type | Default | Description |
|---|---|---|---|
zoom_control |
bool |
true |
Show/hide zoom control buttons |
scroll_wheel_zoom |
bool |
true |
Enable/disable scroll wheel zooming |
double_click_zoom |
bool |
true |
Enable/disable double-click zooming |
touch_zoom |
bool |
true |
Enable/disable touch/pinch zooming |
dragging |
bool |
true |
Enable/disable map dragging |
keyboard |
bool |
true |
Enable/disable keyboard navigation |
attribution_control |
bool |
true |
Show/hide attribution control |
tile_layer |
TileLayer |
OpenStreetMap | Tile layer configuration |
leaflet_resources |
LeafletResources |
CDN v1.9.4 | Leaflet CSS/JS resource configuration |
Tile Layers
Choose from different tile layer providers:
use dioxus_leaflet::TileLayer;
// OpenStreetMap (default)
let osm_tiles = TileLayer::openstreetmap();
// Satellite imagery
let satellite_tiles = TileLayer::satellite();
// Custom tile layer
let custom_tiles = TileLayer {
url: "https://{s}.tile.custom-provider.com/{z}/{x}/{y}.png".to_string(),
attribution: "© Custom Provider".to_string(),
max_zoom: 18,
subdomains: vec!["a".to_string(), "b".to_string()],
};
Event Handling
Handle various map and marker events:
fn App() -> Element {
let mut selected_marker = use_signal(|| None::<MapMarker>);
let mut map_center = use_signal(|| MapPosition::default());
rsx! {
Map {
on_marker_click: move |marker| {
selected_marker.set(Some(marker));
},
on_map_click: move |position| {
println!("Clicked at: {}, {}", position.lat, position.lng);
},
on_map_move: move |position| {
map_center.set(position);
},
// ... other props
}
// Display selected marker info
if let Some(marker) = selected_marker.read().as_ref() {
div {
"Selected: {marker.title}"
if let Some(desc) = &marker.description {
p { "{desc}" }
}
}
}
}
}
Styling
CSS Classes
The component uses these CSS classes that you can style:
.dioxus-leaflet-container- Main container.dioxus-leaflet-map- Map element
Custom Styling
.dioxus-leaflet-container {
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.my-custom-map {
border: 2px solid #007cba;
}
Examples
Basic Map with Custom Leaflet Version
use dioxus::prelude::*;
use dioxus_leaflet::{Map, MapPosition, MapMarker, MapOptions, LeafletResources};
fn App() -> Element {
let markers = vec![
MapMarker::new(51.505, -0.09, "London")
.with_description("Capital of England"),
];
let options = MapOptions::default()
.with_leaflet_resources(LeafletResources::cdn("1.9.3"))
.with_zoom_control(true);
rsx! {
Map {
initial_position: MapPosition::new(51.505, -0.09, 13.0),
markers: markers,
options: options,
height: "400px",
width: "100%"
}
}
}
Map with Local Leaflet Files
use dioxus::prelude::*;
use dioxus_leaflet::{Map, MapPosition, MapMarker, MapOptions, LeafletResources};
fn OfflineMap() -> Element {
let markers = vec![
MapMarker::new(48.8566, 2.3522, "Paris")
.with_description("Capital of France"),
];
let options = MapOptions::default()
.with_leaflet_resources(LeafletResources::local(
"/assets/leaflet/leaflet.css",
"/assets/leaflet/leaflet.js"
));
rsx! {
Map {
initial_position: MapPosition::new(48.8566, 2.3522, 12.0),
markers: markers,
options: options,
height: "500px",
width: "100%"
}
}
}
Tourist Map
use dioxus::prelude::*;
use dioxus_leaflet::{Map, MapPosition, MapMarker, PopupOptions};
fn TouristMap() -> Element {
let attractions = vec![
MapMarker::new(51.5074, -0.1278, "Big Ben")
.with_description("Famous clock tower in London")
.with_popup_options(PopupOptions {
max_width: Some(200),
..Default::default()
}),
MapMarker::new(51.5033, -0.1195, "London Eye")
.with_description("Giant Ferris wheel on the Thames"),
MapMarker::new(51.5194, -0.1270, "British Museum")
.with_description("World-famous museum with artifacts from around the globe"),
];
rsx! {
div { class: "tourist-map-container",
h1 { "London Attractions" }
Map {
initial_position: MapPosition::new(51.5074, -0.1278, 12.0),
markers: attractions,
height: "100vh",
width: "100vw",
class: "attraction-map"
}
}
}
}
Real-time Location Tracking
fn LocationTracker() -> Element {
let mut current_position = use_signal(|| MapPosition::default());
let mut path_markers = use_signal(|| Vec::<MapMarker>::new());
// Simulate location updates
use_future(move || async move {
loop {
tokio::time::sleep(tokio::time::Duration::from_secs(5)).await;
let new_pos = MapPosition::new(
current_position.read().lat + (fastrand::f64() - 0.5) * 0.01,
current_position.read().lng + (fastrand::f64() - 0.5) * 0.01,
current_position.read().zoom,
);
current_position.set(new_pos.clone());
let marker = MapMarker::new(new_pos.lat, new_pos.lng, "Current Location");
path_markers.with_mut(|markers| markers.push(marker));
}
});
rsx! {
Map {
initial_position: current_position.read().clone(),
markers: path_markers.read().clone(),
height: "500px",
on_map_click: move |pos| {
current_position.set(pos);
}
}
}
}
Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
License
This project is licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or Apache 2.0)
- MIT License (LICENSE-MIT or MIT)
at your option.
Acknowledgments
- Leaflet - The amazing mapping library this component wraps
- Dioxus - The reactive UI library for Rust
- OpenStreetMap - Free geographic data used in examples
Note:
Internet Connection Requirements
- CDN mode: Requires internet connection to load Leaflet from CDN (default behavior)
- Local mode: Works offline when using local Leaflet files
Setting Up Local Files
To use local Leaflet files:
- Download Leaflet from leafletjs.com
- Place the CSS and JS files in your static assets directory
- Configure the paths using
LeafletResources::local()
Example directory structure:
static/
├── css/
│ └── leaflet.css
├── js/
│ └── leaflet.js
Usage:
let options = MapOptions::default()
.with_leaflet_resources(LeafletResources::local(
"/static/css/leaflet.css",
"/static/js/leaflet.js"
));
Dependencies
~27–46MB
~701K SLoC