---
title: "How to create a choropleth Map from GeoJSON using Leaflet | Leaflet"
description: "Create a styled choropleth map using GeoJSON and Leaflet."
---

> For AI agents: a documentation index is available at [/llms.txt](https://docs.maptiler.com/llms.txt). Markdown versions of all pages are available by appending .md to any URL.

# How to create a choropleth Map from GeoJSON using Leaflet

This tutorial shows you how to add a styled GeoJSON overlay to your map, adjust the placement of labels, display a popup on click, and create a map legend. We’ll use GeoJSON data from EUROSTAT that includes countries with attributes. To use the same data, [download the sample dataset of average age at first marriage](https://docs.maptiler.com/sdk-js/assets/Mean_age_of_women_at_first_marriage_in_2019.geojson).

1.  Copy the following code, paste it into your favorite text editor, and save it as a `.html` file.
    
    ```html
    <!DOCTYPE html>
     <html>
       <head>
         <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
         <title>Display a choropleth Map from GeoJSON</title>
         <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
         <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
         <style>
           #map {position: absolute; top: 0; right: 0; bottom: 0; left: 0;}
         </style>
       </head>
       <body>
         <div id="map">
           <a href="https://www.maptiler.com" style="position:absolute;left:10px;bottom:10px;z-index:999;"><img src="https://api.maptiler.com/resources/logo.svg" alt="MapTiler logo"></a>
         </div>
         <p><a href="https://www.maptiler.com/copyright/" target="_blank" rel="noopener">&copy; MapTiler</a> <a href="https://www.openstreetmap.org/copyright" target="_blank" rel="noopener">&copy; OpenStreetMap contributors</a></p>
         <script>
           const key = 'YOUR_MAPTILER_API_KEY_HERE';
           const map = L.map('map').setView([52.51, 13.39], 3); //starting position
           L.tileLayer(`https://api.maptiler.com/maps/dataviz-dark/{z}/{x}/{y}.png?key=${key}`,{ //style URL
             tileSize: 512,
             zoomOffset: -1,
             minZoom: 1,
             attribution: "\u003ca href=\"https://www.maptiler.com/copyright/\" target=\"_blank\"\u003e\u0026copy; MapTiler\u003c/a\u003e \u003ca href=\"https://www.openstreetmap.org/copyright\" target=\"_blank\"\u003e\u0026copy; OpenStreetMap contributors\u003c/a\u003e",
             crossOrigin: true
           }).addTo(map);
         </script>
       </body>
     </html>
    ```
    

1.  Install the npm package.
    
    ```bash
    npm install --save leaflet
    ```
    
2.  Include the CSS file.
    
    If you have a bundler that can handle CSS, you can [`import`](#) the CSS or include it with a [`<link>`](#) in the head of the document via the CDN
    
    ```js
    import "leaflet/dist/leaflet.css";
    ```
    
    ```html
    <link href='https://unpkg.com/leaflet@1.9.4/dist/leaflet.css' rel='stylesheet' />
    ```
    
3.  Include the following code in your JavaScript file (Example: main.js).
    
    ```js
    import L from 'leaflet';
        
    const key = 'YOUR_MAPTILER_API_KEY_HERE';
    const map = L.map('map').setView([52.51, 13.39], 3); //starting position
    L.tileLayer(`https://api.maptiler.com/maps/dataviz-dark/{z}/{x}/{y}.png?key=${key}`,{ //style URL
      tileSize: 512,
      zoomOffset: -1,
      minZoom: 1,
      attribution: "\u003ca href=\"https://www.maptiler.com/copyright/\" target=\"_blank\"\u003e\u0026copy; MapTiler\u003c/a\u003e \u003ca href=\"https://www.openstreetmap.org/copyright\" target=\"_blank\"\u003e\u0026copy; OpenStreetMap contributors\u003c/a\u003e",
      crossOrigin: true
    }).addTo(map);
    ```
    

1.  Replace `YOUR_MAPTILER_API_KEY_HERE` with [your own API key](https://cloud.maptiler.com/account/keys/). Make sure to [secure the key](https://docs.maptiler.com/guides/credentials/api-key/#secure-key) before you publish it.
    
2.  The next is up to you. You can center your map wherever you desire (modifying the `starting position`) and set an appropriate zoom level (modifying the `starting zoom`) to match your users’ needs. Additionally, you can change the map’s look (by updating the `source URL`); choose from a range of visually appealing map styles from our extensive [MapTiler standard maps](https://cloud.maptiler.com/maps/), or create your own to truly differentiate your application.
    

1.  Include the [Leaflet-AJAX plugin](https://github.com/calvinmetcalf/leaflet-ajax) JavaScript file in the `<head>` of your HTML file. To add a GeoJSON from an external URL to Leaflet, we will need to use the `Leaflet-AJAX plugin`.
    
    ```html
    <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
     <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-ajax/2.1.0/leaflet.ajax.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
     <style>
    ```
    

1.  Install [Leaflet-AJAX plugin](https://github.com/calvinmetcalf/leaflet-ajax) packages. They make it possible to add a GeoJSON from an external URL to Leaflet.
    
    ```bash
    npm install --save leaflet-ajax
    ```
    
2.  Import the new modules in your JavaScript file (Example: main.js) to add the new functionality.
    
    ```js
    import L from 'leaflet';
       import 'leaflet-ajax';
    ```
    

1.  Add the GeoJSON layer. With Leaflet-AJAX it\`s possible to fetch GeoJSON data hosted on MapTiler (check out the [How to upload GeoJSON](https://docs.maptiler.com/guides/maps-apis/maps-platform/prepare-geojson-with-attributes-for-choropleth-map-and-upload-geojson-to-maptiler-cloud#PrepareGeoJSONwithattributesforchoroplethmapanduploadGeoJSONtoMapTilerCloud-UploadGeoJSONtoMapTilerCloud) tutorial). The GeoJSON example uses data from Eurostat’s Marriage Indicators dataset, filtered to show only countries that have available data on women’s mean age at first marriage in 2019. If you want to use the same sample data, [download the dataset](https://docs.maptiler.com/sdk-js/assets/Mean_age_of_women_at_first_marriage_in_2019.geojson).
    
    ```js
    const geojson = new L.GeoJSON.AJAX(`https://api.maptiler.com/data/YOUR_CUSTOM_MAP_ID/features.json?key=${key}`,{}).addTo(map);
    ```
    
2.  Create the functions to get the style based on the age attribute.
    
    ```js
    function getColor(age) {
         return age > 30 ? '#8c2d04' :
           age > 29  ? '#d94801' :
           age > 28  ? '#f16913' :
           age > 27  ? '#fd8d3c' :
           age > 26  ? '#fdae6b' :
           age > 25  ? '#fdd0a2' :
           age > 24  ? '#fee6ce' :
           '#fff5eb';
       }
       function getStyle(feature) {
         return {
           weight: 1, // size of outline
           opacity: 1, // outline opacity
           color: 'black', // color of outline
           fillOpacity: 1,
           fillColor: getColor(feature.properties.age),
         };
       }
    ```
    
3.  Change the `style` property of the layer.
    
    ```js
    const geojson = new L.GeoJSON.AJAX(`https://api.maptiler.com/data/YOUR_CUSTOM_MAP_ID/features.json?key=${key}`,{
         style: getStyle
       }).addTo(map);
    ```
    
4.  Create a function to display a popup when clicking on the GeoJSON layer and show the information of the age attribute.
    
    ```js
    function popup(feature, layer){
       layer.bindPopup(`<h3>Average age of </br> women at first marriage</br> in 2019</h3><p>${feature.properties.age}</p>`)
     }
    ```
    
5.  Display a popup when clicking on the GeoJSON layer.
    
    ```js
    const geojson = new L.GeoJSON.AJAX(`https://api.maptiler.com/data/YOUR_CUSTOM_MAP_ID/features.json?key=${key}`,{
         onEachFeature:popup,
         style: getStyle
       }).addTo(map);
    ```
    

1.  Create a map legend.
    
    ```html
    <!DOCTYPE html>
       <html>
         <head>
           <meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
           <title>Display a choropleth Map from GeoJSON</title>
           <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
           <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
           <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-ajax/2.1.0/leaflet.ajax.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
           <style>
             #map {position: absolute; top: 0; right: 0; bottom: 0; left: 0;}
             .legend {
               background-color: #000;
               border-radius: 3px;
               bottom: 30px;
               box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
               color: #fff ;
               font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
               padding: 10px;
               position: absolute;
               right: 10px;
               z-index: 800;
             }
             .legend h4 {
               margin: 0 0 10px;
             }
             .legend div span {
               border-radius: 50%;
               display: inline-block;
               height: 10px;
               margin-right: 5px;
               width: 10px;
             }
           </style>
         </head>
         <body>
           <div id="map">
             <a href="https://www.maptiler.com" style="position:absolute;left:10px;bottom:10px;z-index:999;"><img src="https://api.maptiler.com/resources/logo.svg" alt="MapTiler logo"></a>
           </div>
           <p><a href="https://www.maptiler.com/copyright/" target="_blank">&copy; MapTiler</a> <a href="https://www.openstreetmap.org/copyright" target="_blank">&copy; OpenStreetMap contributors</a></p>
           <div id="state-legend" class="legend">
             <h4>Mean age of </br> women at first marriage </br> in 2019 </h4>
             <div><span style="background-color: #fff5eb"></span>23</div>
             <div><span style="background-color: #fee6ce"></span>24</div>
             <div><span style="background-color: #fdd0a2"></span>25</div>
             <div><span style="background-color: #fdae6b"></span>26</div>
             <div><span style="background-color: #fd8d3c"></span>27</div>
             <div><span style="background-color: #f16913"></span>28</div>
             <div><span style="background-color: #d94801"></span>29</div>
             <div><span style="background-color: #8c2d04"></span>30</div>
           </div>
           <script>
    ```
    

1.  Add the map legend style code to your `css` file.
    
    ```css
    .legend {
       background-color: #000;
       border-radius: 3px;
       bottom: 30px;
       box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
       color: #fff ;
       font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
       padding: 10px;
       position: absolute;
       right: 10px;
       z-index: 800;
     }
     .legend h4 {
       margin: 0 0 10px;
     }
     .legend div span {
       border-radius: 50%;
       display: inline-block;
       height: 10px;
       margin-right: 5px;
       width: 10px;
     }
    ```
    
2.  Create the map legend in your `html` file.
    
    ```html
    <div id="state-legend" class="legend">
       <h4>Mean age of </br> women at first marriage </br> in 2019</h4>
       <div><span style="background-color: #fff5eb"></span>23</div>
       <div><span style="background-color: #fee6ce"></span>24</div>
       <div><span style="background-color: #fdd0a2"></span>25</div>
       <div><span style="background-color: #fdae6b"></span>26</div>
       <div><span style="background-color: #fd8d3c"></span>27</div>
       <div><span style="background-color: #f16913"></span>28</div>
       <div><span style="background-color: #d94801"></span>29</div>
       <div><span style="background-color: #8c2d04"></span>30</div>
     </div>
    ```
    

Now you have a basic choropleth map. It doesn’t include country labels on the top of our GeoJSON layer, so it might lack context. If you want to add the labels, continue with the workflow below.

## Display labels over country polygons

On choropleth maps, it’s a good practice to include name labels. It helps users get oriented in the map, especially in areas of the world that are unfamiliar to them.

When we created a choropleth map with Leaflet.js, we basically created an overlay of a basemap, which means that our GeoJSON with marriage data covers the existing country labels. That makes the map challenging to read. Let’s fix it and add the labels back. The picture below shows the difference between a basic choropleth map without labels and a more readable map which we’ll get at the end of this workflow.

![image](./labels.webp)

1.  Prepare a basemap and label layer

MapTiler offers several basemap styles, each designed for a specific purpose. The Dataviz style was intended for data visualization, making it a perfect fit for choropleth maps. Dataviz also comes in a dark version, allowing your content to capture the user’s full focus.

-   To get [Dataviz-dark](https://www.maptiler.com/maps/#style=dataviz-latest-dark), go to [your MapTiler Cloud account](https://cloud.maptiler.com/maps/) and select **New map**.
-   On tab **Simple**, select **Dataviz** and switch to the _dark preset_.
-   Click on **Customize**.

To display labels over GeoJSON, we will need two separate layers: the basemap without labels, and a new layer with labels. Prepare them in the Map Designer tool:

-   In the left menu, select **Layers**.
-   Switch to **Verticality** view.
-   Hide all symbol layers. (The screenshot below shows the icon that marks symbol layers.)
-   **Save** and **publish** the map. Now you’ve got a map without symbols (labels), which you can use as a new basemap in the next step.
-   Repeat the steps above, but this time hide all _non-symbol layers_. This creates a label-only map, which we’ll use as the top layer to display the labels.

Note down the map IDs of both your new maps. On the [Maps page](https://cloud.maptiler.com/maps/), click on your map, which takes you to the map preview page. The URL of this page contains an alphanumeric string which is the map ID. Example: `https://cloud.maptiler.com/maps/0198eca7-644f-7927-825f-e45f2dee80ac/`

![image](./customize-verticality.webp)

1.  Replace your current basemap with your new map _without_ labels. You’ll need the map ID from the previous step.

```js
const map = L.map("map").setView([24.65605, 9.16266], 2);
L.tileLayer(
  "https://api.maptiler.com/maps/YOUR_NO_LABEL_MAP_ID/{z}/{x}/{y}.png?key=${key}",
  {
    tileSize: 512,
    zoomOffset: -1,
    minZoom: 1,
    attribution:
      '\u003ca href="https://www.maptiler.com/copyright/" target="_blank"\u003e\u0026copy; MapTiler\u003c/a\u003e \u003ca href="https://www.openstreetmap.org/copyright" target="_blank"\u003e\u0026copy; OpenStreetMap contributors\u003c/a\u003e',
    crossOrigin: true,
  }
).addTo(map);
```

1.  Create the label layer by using the other map you’ve created, with labels only.

```js
const labels = L.tileLayer(
  "https://api.maptiler.com/maps/YOUR_ONLY_LABEL_MAP_ID/{z}/{x}/{y}.png?key=${key}",
  {
    tileSize: 512,
    zoomOffset: -1,
    minZoom: 1,
    attribution:
      '\u003ca href="https://www.maptiler.com/copyright/" target="_blank"\u003e\u0026copy; MapTiler\u003c/a\u003e \u003ca href="https://www.openstreetmap.org/copyright" target="_blank"\u003e\u0026copy; OpenStreetMap contributors\u003c/a\u003e',
    crossOrigin: true,
  }
).addTo(map);
```

1.  Create a pane for labels.

[Panes](https://leafletjs.com/examples/map-panes/) define in which order the layers get displayed.

For the pane, we define `z-index`, which specifies which panes can overlap our new labels pane. With `z-index` 550, our labels can be overlapped with markers, tooltips, and popups. This table shows the default pane settings:

| Pane | Z-index | Description |
| --- | --- | --- |
| `mapPane` | `'auto'` | The pane that contains all other map panes |
| `tilePane` | `200` | Pane for `GridLayer`s and `TileLayer`s |
| `overlayPane` | `400` | Pane for overlay shadows (e.g. `Marker` shadows) |
| `shadowPane` | `500` | Pane for vectors (`Path`s, like `Polyline`s and `Polygon`s), `ImageOverlay`s,  `VideoOverlay`s, circles, and **GeoJSONs** |
| `markerPane` | `600` | Pane for `Icon`s of `Marker`s |
| `tooltipPane` | `650` | Pane for `Tooltip`s |
| `popupPane` | `700` | Pane for `Popup`s |

The labels are a raster tile layer that covers the entire map and will capture clicks and touches. If you click anywhere on the map, the web browser will assume that you clicked on the labels layer, not the GeoJSON layer, and the pop-up will not appear. We can fix the pop-up appearance by using the `pointer-events`. _Tip: If you want to avoid this issue completely, switch to a different mapping library (e.g. [MapTiler SDK](https://docs.maptiler.com/sdk-js/) or Openlayers) that supports vector tiles by default. Raster tiles return a raster layer (an image containing all layers) while vector tiles returns geometries; the benefit of geometries is that the layers stay separate and can be easily styled on the fly._

```js
map.createPane("labels");
map.getPane("labels").style.zIndex = 550;
map.getPane("labels").style.pointerEvents = "none";

const labels = L.tileLayer(
```

1.  Assign a label pane to the label tiles definition.

```js
const labels = L.tileLayer(`https://api.maptiler.com/maps/YOUR_ONLY_LABEL_MAP_ID/{z}/{x}/{y}.png?key=${key}`, { //style URL
    tileSize: 512,
    zoomOffset: -1,
    minZoom: 1,
    attribution: "\u003ca href=\"https://www.maptiler.com/copyright/\" target=\"_blank\"\u003e\u0026copy; MapTiler\u003c/a\u003e \u003ca href=\"https://www.openstreetmap.org/copyright\" target=\"_blank\"\u003e\u0026copy; OpenStreetMap contributors\u003c/a\u003e",
    crossOrigin: true,
    pane: 'labels'
  }).addTo(map);
```

Now your choropleth map should show country name labels nicely.

### Complete source code

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Display a choropleth Map from GeoJSON</title>
  <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
  <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-ajax/2.1.0/leaflet.ajax.min.js" crossorigin="anonymous"
    referrerpolicy="no-referrer"></script>
  <style>
    body { margin: 0; padding: 0; }
    #map { position: absolute; top: 0; bottom: 0; width: 100%; }

    .legend {
      background-color: #000;
      border-radius: 3px;
      bottom: 30px;
      box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
      color: #fff;
      font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
      padding: 10px;
      position: absolute;
      right: 10px;
      z-index: 800;
    }

    .legend h4 {
      margin: 0 0 10px;
    }

    .legend div span {
      border-radius: 50%;
      display: inline-block;
      height: 10px;
      margin-right: 5px;
      width: 10px;
    }
  </style>
</head>
<body>
  <div id="map"></div>
  <p><a href="https://www.maptiler.com/copyright/" target="_blank">&copy; MapTiler</a> <a
      href="https://www.openstreetmap.org/copyright" target="_blank">&copy; OpenStreetMap contributors</a></p>
  <div id="state-legend" class="legend">
    <h4>Mean age of </br> women at first marriage </br> in 2019</h4>
    <div><span style="background-color: #fff5eb"></span>23</div>
    <div><span style="background-color: #fee6ce"></span>24</div>
    <div><span style="background-color: #fdd0a2"></span>25</div>
    <div><span style="background-color: #fdae6b"></span>26</div>
    <div><span style="background-color: #fd8d3c"></span>27</div>
    <div><span style="background-color: #f16913"></span>28</div>
    <div><span style="background-color: #d94801"></span>29</div>
    <div><span style="background-color: #8c2d04"></span>30</div>
  </div>
</body>
<script>
  const key = 'YOUR_MAPTILER_API_KEY_HERE';

  const map = L.map('map').setView([0, 0], 2);
  const layer = L.tileLayer(`https://api.maptiler.com/maps/YOUR_NO_LABEL_MAP_ID/{z}/{x}/{y}.png?key=${key}`, {
    tileSize: 512,
    zoomOffset: -1,
    minZoom: 1,
    attribution: "\u003ca href=\"https://www.maptiler.com/copyright/\" target=\"_blank\"\u003e\u0026copy; MapTiler\u003c/a\u003e \u003ca href=\"https://www.openstreetmap.org/copyright\" target=\"_blank\"\u003e\u0026copy; OpenStreetMap contributors\u003c/a\u003e",
    crossOrigin: true
  }).addTo(map);

  map.createPane("labels");
  map.getPane("labels").style.zIndex = 550;
  map.getPane("labels").style.pointerEvents = "none";

  const labels = L.tileLayer(`https://api.maptiler.com/maps/YOUR_ONLY_LABEL_MAP_ID/{z}/{x}/{y}.png?key=${key}`, { //style URL
    tileSize: 512,
    zoomOffset: -1,
    minZoom: 1,
    attribution: "\u003ca href=\"https://www.maptiler.com/copyright/\" target=\"_blank\"\u003e\u0026copy; MapTiler\u003c/a\u003e \u003ca href=\"https://www.openstreetmap.org/copyright\" target=\"_blank\"\u003e\u0026copy; OpenStreetMap contributors\u003c/a\u003e",
    crossOrigin: true,
    pane: 'labels'
  }).addTo(map);

  function getColor(age) {
    return age > 30 ? '#8c2d04' :
      age > 29 ? '#d94801' :
        age > 28 ? '#f16913' :
          age > 27 ? '#fd8d3c' :
            age > 26 ? '#fdae6b' :
              age > 25 ? '#fdd0a2' :
                age > 24 ? '#fee6ce' :
                  '#fff5eb';
  }
  function getStyle(feature) {
    return {
      weight: 1, //size of outline
      opacity: 1, //outline opacity
      color: 'black', //colour of outline
      fillOpacity: 1,
      fillColor: getColor(feature.properties.age),
    };
  }
  function popup(feature, layer) {
    layer.bindPopup(`<h3>Average age of </br> women at first marriage</br> in 2019</h3><p>${feature.properties.age}</p>`)
  }
  const geojson = new L.GeoJSON.AJAX(`https://api.maptiler.com/data/55336072-ef0f-4cb5-8671-b8d6ebbb0a05/features.json?key=${key}`, {
    onEachFeature: popup,
    style: getStyle
  }).addTo(map);
</script>

</html>
```

### Complete source code

```bash
npm install --save leaflet leaflet-ajax
```

#### main.js

```js
import L from 'leaflet';
import 'leaflet/dist/leaflet.css';
import 'leaflet-ajax'

const key = 'YOUR_MAPTILER_API_KEY_HERE';

const map = L.map('map').setView([0, 0], 2);
const layer = L.tileLayer(`https://api.maptiler.com/maps/YOUR_NO_LABEL_MAP_ID/{z}/{x}/{y}.png?key=${key}`, {
  tileSize: 512,
  zoomOffset: -1,
  minZoom: 1,
  attribution: "\u003ca href=\"https://www.maptiler.com/copyright/\" target=\"_blank\"\u003e\u0026copy; MapTiler\u003c/a\u003e \u003ca href=\"https://www.openstreetmap.org/copyright\" target=\"_blank\"\u003e\u0026copy; OpenStreetMap contributors\u003c/a\u003e",
  crossOrigin: true
}).addTo(map);

map.createPane("labels");
map.getPane("labels").style.zIndex = 550;
map.getPane("labels").style.pointerEvents = "none";

L.tileLayer(`https://api.maptiler.com/maps/YOUR_ONLY_LABEL_MAP_ID/{z}/{x}/{y}.png?key=${key}`, { //style URL
  tileSize: 512,
  zoomOffset: -1,
  minZoom: 1,
  attribution: "\u003ca href=\"https://www.maptiler.com/copyright/\" target=\"_blank\"\u003e\u0026copy; MapTiler\u003c/a\u003e \u003ca href=\"https://www.openstreetmap.org/copyright\" target=\"_blank\"\u003e\u0026copy; OpenStreetMap contributors\u003c/a\u003e",
  crossOrigin: true,
  pane: 'labels'
}).addTo(map);

function getColor(age) {
  return age > 30 ? '#8c2d04' :
    age > 29 ? '#d94801' :
      age > 28 ? '#f16913' :
        age > 27 ? '#fd8d3c' :
          age > 26 ? '#fdae6b' :
            age > 25 ? '#fdd0a2' :
              age > 24 ? '#fee6ce' :
                '#fff5eb';
}
function getStyle(feature) {
  return {
    weight: 1, //size of outline
    opacity: 1, //outline opacity
    color: 'black', //colour of outline
    fillOpacity: 1,
    fillColor: getColor(feature.properties.age),
  };
}
function popup(feature, layer) {
  layer.bindPopup(`<h3>Average age of </br> women at first marriage</br> in 2019</h3><p>${feature.properties.age}</p>`)
}
const geojson = new L.GeoJSON.AJAX(`https://api.maptiler.com/data/55336072-ef0f-4cb5-8671-b8d6ebbb0a05/features.json?key=${key}`, {
  onEachFeature: popup,
  style: getStyle
}).addTo(map);
```

#### index.html

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="robots" content="noindex">
  <title>Display a choropleth Map from GeoJSON</title>
  <link rel="stylesheet" href="./style.css">
</head>
<body>
  <div id="map"></div>
  <p><a href="https://www.maptiler.com/copyright/" target="_blank">&copy; MapTiler</a> <a
      href="https://www.openstreetmap.org/copyright" target="_blank">&copy; OpenStreetMap contributors</a></p>
  <div id="state-legend" class="legend">
    <h4>Mean age of </br> women at first marriage </br> in 2019</h4>
    <div><span style="background-color: #fff5eb"></span>23</div>
    <div><span style="background-color: #fee6ce"></span>24</div>
    <div><span style="background-color: #fdd0a2"></span>25</div>
    <div><span style="background-color: #fdae6b"></span>26</div>
    <div><span style="background-color: #fd8d3c"></span>27</div>
    <div><span style="background-color: #f16913"></span>28</div>
    <div><span style="background-color: #d94801"></span>29</div>
    <div><span style="background-color: #8c2d04"></span>30</div>
  </div>
  <script type="module" src="./main.js"></script>
</body>
</html>
```

#### style.css

```css
body {
  margin: 0;
  padding: 0;
}

#map {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 100%;
}

.legend {
  background-color: #000;
  border-radius: 3px;
  bottom: 30px;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
  color: #fff;
  font: 12px/20px 'Helvetica Neue', Arial, Helvetica, sans-serif;
  padding: 10px;
  position: absolute;
  right: 10px;
  z-index: 800;
}

.legend h4 {
  margin: 0 0 10px;
}

.legend div span {
  border-radius: 50%;
  display: inline-block;
  height: 10px;
  margin-right: 5px;
  width: 10px;
}
```

## Learn more

Check out the following how-tos related to choropleth maps:

-   [How to style a choropleth map in the visual editor Map Designer](https://docs.maptiler.com/sdk-js/examples/countries-with-own-data/)
-   [How to prepare GeoJSON with attributes for choropleth map and upload it to MapTiler](https://docs.maptiler.com/guides/maps-apis/maps-platform/prepare-geojson-with-attributes-for-choropleth-map-and-upload-geojson-to-maptiler-cloud)

## Related examples

### [GeoJSON Layer](https://docs.maptiler.com/leaflet/examples/geojson-polygon/)

Tutorials

Add GeoJSON polygon overlays to Leaflet JS maps.
