I'm adding a vector tile source to my Mapbox GL js map like this:

    this.map.on('load', () => {
        this.map.addSource('userSource', {
            type: 'vector',
            url: 'mapbox://<my user source>',

            id: 'userDataLayer',
            type: 'fill',
            source: 'userSource',
            'source-layer': 'foobar_areas',
            paint: {
                'fill-outline-color': 'rgba(50,50,150,.4)',
                'fill-color': 'rgba(10,190,20,.2)',

I want to initialize some other modules once userDataLayer is ready to go, but I don't know what event to listen for. I tried this:

this.map.on('data', (e) => { 
    const { dataType, sourceId, isSourceLoaded } = e; 
        if (dataType === 'source' && sourceId === 'userSource' && isSourceLoaded) {
        // ...

Except that fires many times... and then fires again when you apply filters, etc.

Is there an event that fires just when the source is loaded?

5 Answers 5


You can use below line of code

   //your code here 

Once all the rendering part has been done then the above function will be called and then you can perform other operations.

For reference, you can follow the link : Mapbox Documentation Link

  • I haven't tried that yet because it was just added in v0.52.0, but that sounds very promising!
    – DMack
    Mar 7, 2019 at 0:45
  • 1
    The 'idle' event did the trick for me (I'm using v2.0.1+ at this point) - I was going in circles trying to make sense of the 'sourcedata' events, 'isSourceLoaded()', 'areTilesLoaded()', etc. and finding no clean solution. The 'idle' event however seems like a rock-solid indicator that the map and layers are done rendering. Jan 19, 2021 at 23:47
  • My question was from 2017, but nowadays the "idle" event is the best solution. Since there's still activity on this question, I'll mark this as the accepted answer to avoid leading new people astray
    – DMack
    Aug 23, 2021 at 16:16

I was dealing with this again today, so here's an update!

As of mapbox-gl v0.44.2, it's still not quite reliable enough to listen for the sourcedata event and check the properties of the event parameter that gets passed to the callback, even though I think that's what you're supposed to do. You'd want to check sourceId === 'your-source-id', isSourceLoaded === true, and sourceDataType !== 'metadata'. If an event satisfied these 3 things, you could assume your source is loaded and ready to work with.

I've been experimenting with this technique, and I found that switching the source at runtime doesn't always fire a sourcedata event that satisfies these criteria. It's a real hassle.

The most solid solution I've been able to find so far is to listen for sourcedata events, but use map.isSourceLoaded every single time to check if your particular source is ready.


function sourceCallback() {
    // assuming 'map' is defined globally, or you can use 'this'
    if (map.getSource('my-data') && map.isSourceLoaded('my-data')) {
        console.log('source loaded!');

map.on('sourcedata', sourceCallback);

The solution is to use the undocumented style.load event that fires when new things finish loading into the style.

map.once('style.load', (ev) => {
    // ...
  • 1
    i wonder why this event is not documented ?!! Mar 1, 2018 at 12:05
  • I know that using the undocumented style.load event is discouraged, so I've added a new answer that is hopefully less hack-ish. I really hope future versions of mapbox-gl simplify things with promises or async methods!
    – DMack
    May 7, 2018 at 23:22
  • I used map.once('sourcedata', function(){}) as style.load did not work for me. And "once" is a great option to solve the problem of the event firing multiple times.
    – neelmeg
    Oct 8, 2021 at 14:49
  • It's now documented: "Fired immediately after all style resources have been downloaded and the first visually complete rendering of the base style has occurred." Feb 28 at 14:51

Answer in 2020 in Typescript

Bind the event once in constructor

this.instance.on('sourcedata', this.sectionSourceAddedCallback);

and inside callback

private sectionSourceAddedCallback = (e: mapboxgl.EventData): void => {
        if (map.getSource('sectionVectorSource') && 
            map.isSourceLoaded('sectionVectorSource') && 
            const features = getSectionFeatures(this.instance); //get data using queryRenderedFeatures... etc..
            this.instance.off('sourcedata', this.sectionSourceAddedCallback); //Unbind event here

Other Useful Link, Check: https://github.com/mapbox/mapbox-gl-js/issues/1715


The answer in 2019 is:

map.once('styledata', loadTiles); //The listener will be called first time the event fires after the listener is registered.

      map.once('styledata', loadTiles);   //The listener will be called first time the event fires after the listener is registered.

     map.on("styledata", loadTiles);    // will fire multiple 3 times, whenever style changed.  
                                // event.stopPropagation(); does not work.

     map.on("load", loadTiles);       // only fire 1 time. but when you change base map, use below

  map.setStyle('mapbox://styles/mapbox/' + layerId, {diff: false});

    //  on load event will not fire, which I need it fire to re-load geojson layer. 

       map.on("styledata"    // works fine, but it fire 3 same event at same time, cause load 3 times geojson layer, cause other error when you load 3 times geojson layer at same time.
  • styledata fires any time the style loads or changes, so you can't guarantee that your style will be loaded when this fires. It's much safer to use load or the idle event depending on your situation.
    – DMack
    Oct 4, 2019 at 22:45
  • that is why I use 'map.once' above, if you use map.on, you will get 3 continues same event, which I do not want to. So I use 'once' will only get 1 event, every register. That means, if you want to get that fired next time, you have to register it again, and get another event fired. So use 'once' will prevent you get multiple event.
    – hoogw
    Oct 7, 2019 at 15:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.