Skip to content
Add a New Layer Below Labels

Add a New Layer Below Labels in Maptoolkit Maps JS

When you add a fill or polygon layer to a map, it covers the label layers and makes the map hard to read. Maptoolkit Maps JS lets you specify an insertion point for new layers so they appear below labels but above the base tiles. Pass the ID of the first symbol layer as the beforeId parameter when calling addLayer to keep your data visible without obscuring place names and road labels.

const API_KEY = 'YOUR_API_KEY';

    const map = new maptoolkit.Map({
        container: 'map',
        apiKey: API_KEY,
        style: `https://styles.maptoolkit.net/maptoolkit/maptoolkit.summer.json?api_key=${API_KEY}`,
        center: [-88.13734351262877, 35.137451890638886],
        zoom: 4,
        attributionControl: { compact: false }
    });

    map.addControl(new maptoolkit.NavigationControl(), 'top-right');

    map.on('load', () => {
        const layers = map.getStyle().layers;
        let firstSymbolId;
        for (const layer of layers) {
            if (layer.type === 'symbol') {
                firstSymbolId = layer.id;
                break;
            }
        }

        map.addSource('urban-areas', {
            type: 'geojson',
            data: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_50m_urban_areas.geojson'
        });

        map.addLayer({
            id: 'urban-areas-fill',
            type: 'fill',
            source: 'urban-areas',
            paint: {
                'fill-color': '#f08',
                'fill-opacity': 0.4
            }
        }, firstSymbolId);
    });
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Add a New Layer Below Labels - Maptoolkit Maps JS</title>
    <meta property="og:description" content="Insert a new data layer below the map's label layers so labels stay visible." />
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://unpkg.com/@maptoolkit/maps@11.0.0-beta.3/dist/maptoolkit.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/@maptoolkit/maps@11.0.0-beta.3/dist/maptoolkit.css" />
    <style>
        html, body { width: 100%; height: 100%; margin: 0; padding: 0; }
        #map { width: 100%; height: 100%; }
    </style>
</head>
<body>
<div id="map"></div>
<script>
    const API_KEY = 'YOUR_API_KEY';

    const map = new maptoolkit.Map({
        container: 'map',
        apiKey: API_KEY,
        style: `https://styles.maptoolkit.net/maptoolkit/maptoolkit.summer.json?api_key=${API_KEY}`,
        center: [-88.13734351262877, 35.137451890638886],
        zoom: 4,
        attributionControl: { compact: false }
    });

    map.addControl(new maptoolkit.NavigationControl(), 'top-right');

    map.on('load', () => {
        const layers = map.getStyle().layers;
        let firstSymbolId;
        for (const layer of layers) {
            if (layer.type === 'symbol') {
                firstSymbolId = layer.id;
                break;
            }
        }

        map.addSource('urban-areas', {
            type: 'geojson',
            data: 'https://d2ad6b4ur7yvpq.cloudfront.net/naturalearth-3.3.0/ne_50m_urban_areas.geojson'
        });

        map.addLayer({
            id: 'urban-areas-fill',
            type: 'fill',
            source: 'urban-areas',
            paint: {
                'fill-color': '#f08',
                'fill-opacity': 0.4
            }
        }, firstSymbolId);
    });
</script>
</body>
</html>

Use the prompt below with any LLM to get the same result. Make sure the Maptoolkit MCP server is connected first — check out AI Integration & MCP to get started.

Use the Maptoolkit Connector. Create an interactive map with zoom level 4, centered around [-88.137, 35.137]. Add a GeoJSON fill layer of urban areas (from Natural Earth data) inserted below the map’s label layers.

How it works

The firstSymbolId lookup is the part to copy. addLayer appends to the top of the style unless you pass a layer id to insert before, so without it the new layer covers every place name and road label on the map. Finding the first symbol layer and inserting below it keeps labels readable.

The loop reads map.getStyle().layers and stops at the first entry whose type is symbol. Hard-coding a layer id instead would break whenever the style changes, and our seven styles do not share layer ids.

This runs inside map.on('load') because the style has to be parsed before its layers can be inspected.

Next steps

Insertion order is worth thinking about once rather than per layer. Most maps end up with a rough stack, fills below lines below your own symbols below the basemap’s labels, and picking two or three insertion points up front saves rearranging later.

With the layer in the right place, the next step is what it shows: colour driven from the data, a filter for the subset that matters, or a click that reports what was hit.