| Crates.io | dioxus-leaflet |
| lib.rs | dioxus-leaflet |
| version | 0.3.1 |
| created_at | 2025-08-10 23:04:46.68968+00 |
| updated_at | 2025-12-16 16:59:28.751894+00 |
| description | A general-purpose Leaflet map component for Dioxus applications |
| homepage | https://github.com/lheintzmann1/dioxus-leaflet |
| repository | https://github.com/lheintzmann1/dioxus-leaflet |
| max_upload_size | |
| id | 1789387 |
| size | 248,114 |
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.




Add this to your Cargo.toml:
[dependencies]
dioxus-leaflet = "0.3.0"
dioxus = "0.7.0-rc.2"
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);
}
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"
}
}
}
}
| 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 |
Configure how Leaflet CSS and JavaScript files are loaded. You can use CDN with specific versions or provide local files.
// Default configuration uses Leaflet 1.9.4 from unpkg.com
let options = MapOptions::default();
use dioxus_leaflet::{MapOptions, LeafletResources};
let options = MapOptions::default()
.with_leaflet_resources(LeafletResources::cdn("1.9.3"));
let options = MapOptions::default()
.with_leaflet_resources(
LeafletResources::cdn_with_base_url("1.9.4", "https://cdn.jsdelivr.net/npm")
);
let options = MapOptions::default()
.with_leaflet_resources(LeafletResources::local(
"/static/css/leaflet.css",
"/static/js/leaflet.js"
));
| 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.
let marker = MapMarker::new(51.505, -0.09, "London");
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()
});
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);
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
}
}
| 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 |
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()],
};
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}" }
}
}
}
}
}
The component uses these CSS classes that you can style:
.dioxus-leaflet-container - Main container.dioxus-leaflet-map - Map element.dioxus-leaflet-container {
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.my-custom-map {
border: 2px solid #007cba;
}
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%"
}
}
}
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%"
}
}
}
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"
}
}
}
}
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);
}
}
}
}
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.
This project is licensed under either of:
at your option.
Note:
To use local Leaflet files:
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"
));