# ngx-leaflet binds Leaflet to Angular, and reads your map options once

> The @bluehalo/ngx-leaflet package gives Angular applications Leaflet maps through directives and inputs, with a layers control, custom layers and support for both Leaflet 0.7 and 1.x, but the map options object is consumed by the map constructor and never re-read. It suits Angular teams who want Leaflet's API without hand wiring it.

**bluehalo/ngx-leaflet** — Core Leaflet package for Angular.io

- Repository: https://github.com/bluehalo/ngx-leaflet
- Stars: 814 · Forks: 134
- Language: TypeScript
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/bluehalo-ngx-leaflet

## The package name tells you the shape of the thing

The README describes @bluehalo/ngx-leaflet as Leaflet packages for Angular.io, providing flexible and extensible components for integrating Leaflet v0.7.x and v1.x into Angular.io projects. Two things follow from that description. The library is a binding layer, not a reimplementation, so anything Leaflet can draw, it can draw, including markers, shapes, geojson and custom layers from other libraries, and the README states that the overlays map accepts any kind of Leaflet layer you want. The second is that this is an Angular library in the older idiom, a directive that attaches to a DOM element and takes inputs, rather than a modern component with its own template. The documentation is organised to match, with a separate API page, a cookbook and an extensions page under `docs/`.

## Three installs, and the typings are separate

Installation is by npm or yarn, and Leaflet itself is a peer dependency that you install yourself:

```bash
npm install leaflet
npm install @bluehalo/ngx-leaflet
```

There is a third install that only applies to TypeScript projects. If you intend to use the library with the typings, you also need the Leaflet type definitions, and the README gives that as a dev dependency:

```bash
npm install --save-dev @types/leaflet
```

The package manifest confirms the shape of the dependency set. `leaflet` is pinned to major version 1 and `@types/leaflet` to 1, and the Angular packages are all on major version 22, with rxjs on 7 and zone.js on 0.16. The manifest also carries a private flag, which is normal for a workspace root that publishes a library from a subproject rather than the root package. If you are not on the latest Angular, the README points at `CHANGES.md` to find the version that matches your project.

## The stylesheet step that decides whether the map works

Leaflet needs its CSS loaded, and the README is unusually clear that this is not optional, since the map will not render correctly without it. If you are building a plain page with no bundler for your CSS, you link the file directly in the HTML:

```html
<head>
	...
	<link rel="stylesheet" type="text/css" href="./node_modules/leaflet/dist/leaflet.css">
	...
</head>
```

With Angular CLI you add the same file to the styles array in `angular.json`:

```json
{
	...
	"styles": [
		"styles.css",
		"./node_modules/leaflet/dist/leaflet.css"
	],
	...
}
```

The one extra wrinkle the README flags is markers. Leaflet marker URLs do not play well with the Angular CLI build pipeline without special handling, and the fix is a documented marker setup in the cookbook rather than something the package does for you. That is the kind of detail that separates a wrapper from a smooth integration, and it is worth reading before you blame the library for a broken pin on the map.

## Standalone components or NgModule, and then a DOM element

Importing the package works the way it works in current Angular, either by importing the directive into a standalone component:

```typescript
import { LeafletDirective } from '@bluehalo/ngx-leaflet';

@Component({
    imports: [
        LeafletDirective // Import the LeafletDirective here
        // import other directives as needed
    ],
})
```

or by importing the module in an NgModule:

```typescript
import { LeafletModule } from '@bluehalo/ngx-leaflet';

@NgModule({
    imports: [
        LeafletModule // Import the LeafletModule here
    ],
})
```

The map itself is not a component you place. You apply the `leaflet` attribute directive to an existing DOM element, and you have to give that element a height, because otherwise it renders with a zero pixel height. That is the whole usage model, and the two other ways of configuring the map are the `leafletOptions` input, or binding `leafletZoom`, `leafletCenter` and `leafletLayers` separately.

## The options object is read once, and that is the sharp edge

This is the constraint that decides how you structure the component. The README states that changes to `leafletOptions` are ignored after they are initially set, because the options are passed into the map constructor and so cannot be changed anyway, and it advises making sure the object exists before the map is created, either by creating it in `ngOnInit` or by hiding the map DOM element with `@if` until the options object exists. The template is small, which is the point:

```html
<div style="height: 300px;"
     leaflet 
     [leafletOptions]="options">
</div>
```

and the options object is a plain Leaflet configuration with layers, zoom and center:

```typescript
options = {
	layers: [
		tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 18, attribution: '...' })
	],
	zoom: 5,
	center: latLng(46.879966, -121.726909)
};
```

The consequence for application design is direct. A map that needs to react to a changed centre or a new layer set cannot do it by mutating the options object. You destroy and recreate the map, or you use the separate bindings for zoom, centre and layers, which are inputs rather than constructor arguments.

## The layers control and layers that never appear in it

Two input bindings cover the map's layer story, and they are deliberately different. The `[leafletLayersControl]` binding adds the control that lets the user toggle base layers and overlays on and off:

```html
<div style="height: 300px;"
     leaflet 
     [leafletOptions]="options"
     [leafletLayersControl]="layersControl">
</div>
```

The control object has `baseLayers` and `overlays` maps, and the overlays can hold anything, including markers, shapes, geojson and custom layers from other libraries. Separately, the `[leafletLayers]` directive adds layers to the map without showing them in the control, which is what you want for a layer that is part of the application state rather than a user choice. Both are inputs, so unlike `leafletOptions` they can change during the life of the map, and the layers control is a separate directive, `LeafletLayersControlDirective`, that you import alongside the base one.

## A library with a demo, a cookbook and a five year gap in its changelog

The repository shows a conventional Angular library layout with an `angular.json`, a `projects/` directory for the library, `src/` for the demo application, `karma.conf.js` for tests, a `docs/` directory for the API page, the cookbook and the extensions, and a `CHANGES.md`. The build script compiles the library with ng-packagr in production mode and copies the README, LICENSE and CHANGES files into the distribution, and the test script runs the Karma and Jasmine suite. The demo is a separate target, `ng serve ngx-leaflet-demo`, and the README explains how to run it after cloning: an `npm install`, an `npm run demo`, and then a browser on port 4200. The licence is MIT. There are no GitHub releases, and the last push to the repository was on 2026-09-11, so the version of the package you get from npm and the version on the default branch can differ.

## Conclusion

Adopt @bluehalo/ngx-leaflet when your Angular application needs Leaflet maps and you want the Leaflet API rather than a map abstraction, since the package passes through layers, shapes and custom layers and covers Leaflet 0.7 and 1.x. Do not adopt it if you need the map to react to option changes after creation, because the README states that changes to `leafletOptions` are ignored after they are initially set. Verify first that the stylesheet is loaded through your build, since a missing Leaflet CSS file is the most common cause of a broken map, and check `CHANGES.md` if you are on an older Angular version than the current one.

## FAQ

### How do I install ngx-leaflet in an Angular project?

Install Leaflet and the package with npm or yarn, `npm install leaflet` and `npm install @bluehalo/ngx-leaflet`. For a TypeScript project that uses the typings, also add `npm install --save-dev @types/leaflet`.

### Why does my ngx-leaflet map show no markers or tiles?

The README notes that Leaflet marker URLs do not play well with the Angular CLI build pipeline without special handling, and points at the marker setup section in the cookbook for the configuration steps. It also stresses that the Leaflet stylesheet must be loaded, either as a link in the HTML or through the styles array in `angular.json`.

### Can I change the map options after the map is created?

No. The README states that changes to `leafletOptions` are ignored after they are initially set, because the options are passed into the map constructor. Create the object in `ngOnInit`, or hide the map element with `@if` until the object exists, and use the separate `leafletZoom`, `leafletCenter` and `leafletLayers` bindings for reactive values.

### Which Leaflet versions does ngx-leaflet support?

The README says the package provides components for integrating Leaflet v0.7.x and v1.x into Angular projects. The package manifest pins `leaflet` to major version 1.

## Sources

- [bluehalo/ngx-leaflet on GitHub](https://github.com/bluehalo/ngx-leaflet)
- [Issues](https://github.com/bluehalo/ngx-leaflet/issues)
- [License: MIT](https://github.com/bluehalo/ngx-leaflet/blob/master/LICENSE)
- [README](https://github.com/bluehalo/ngx-leaflet/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/bluehalo-ngx-leaflet
