<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>topic Re: Basemap Gallery component - Add basemap from tile layer in ArcGIS JavaScript Maps SDK Questions</title>
    <link>https://community.esri.com/t5/arcgis-javascript-maps-sdk-questions/basemap-gallery-component-add-basemap-from-tile/m-p/1680915#M88104</link>
    <description>&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;This is how I am adding custom basemaps gallery:&lt;/P&gt;&lt;LI-CODE lang="javascript"&gt;import { BASEPATH_URL_PATH } from "@/config/basepath.config";

export const basemapConfigs = {
    // WebTileLayer (XYZ/TMS tiles from mbtiles)
    customtiles: {
        id: 'custom-tiles',
        title: 'Custom Tiles',
        url: 'https://mydomain.com/mbtiles/custom.mbtiles/{z}/{x}/{y}',
        thumbnail: `${BASEPATH_URL_PATH}/basemaps/BasemapDefault.png`,
        type: 'custom_webtile', // indicates this is an XYZ/TMS tile layer
        minZoom: 9,
        maxZoom: 18,
    },
    // TileLayer
    default: {
        id: 'default',
        title: 'Basemap2',
        url: 'https://mydomain.com/server/rest/services/Basemap/Basemap/MapServer',
        thumbnail: `${BASEPATH_URL_PATH}/basemaps/BasemapDefault.png`,
    },
    // TileLayer
    aerial: {
        id: 'base-aerial',
        title: 'Aerial',
        url: 'https://mydomain.com/server/rest/services/Basemap/BasemapAerial/MapServer',
        thumbnail: `${BASEPATH_URL_PATH}/basemaps/BasemapAerial.png`,
    },
    // TileLayer
    grayscale: {
        id: 'grayscale',
        title: 'Grayscale',
        url: 'https://mydomain.com/server/rest/services/Basemap/BasemapGrayscale/MapServer',
        thumbnail: `${BASEPATH_URL_PATH}/basemaps/BasemapGrayscale.png`,
    },
    // TileLayer
    topohillshade: {
        id: 'topohillshade',
        title: 'TopoHillShade',
        url: 'https://mydomain.com/server/rest/services/Basemap/TopoHillShade/MapServer',
        thumbnail: `${BASEPATH_URL_PATH}/basemaps/TopoHillShade.png`,
    },
};&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;In map store:&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="javascript"&gt;import { basemapConfigs } from "@/config/basemap.configs";
import Basemap from "@arcgis/core/Basemap";
import MapImageLayer from "@arcgis/core/layers/MapImageLayer";
import TileLayer from "@arcgis/core/layers/TileLayer";
import WebTileLayer from "@arcgis/core/layers/WebTileLayer";
import LocalBasemapsSource from "@arcgis/core/widgets/BasemapGallery/support/LocalBasemapsSource";
import { create } from "zustand";
import BaseTileLayer from "@arcgis/core/layers/BaseTileLayer";

/**
 * Helper function to convert zoom level to scale
 * Using Web Mercator scale approximation
 */
const getScaleFromZoom = (zoom) =&amp;gt; {
  const earthCircumference = 40075016.686; // meters
  const tileSize = 256;
  return earthCircumference / (tileSize * Math.pow(2, zoom));
};

export const useMapStore = create((set, get) =&amp;gt; ({
  mapElement: null,
  basemap: basemapConfigs.default,
  loading: true,
  map: null,
  view: null,
  gallery: null,

  setMapElement: (el) =&amp;gt; {
    const gallery = el?.querySelector("arcgis-basemap-gallery");
    const map = document.querySelector("arcgis-map")?.map;
    const view = document.querySelector("arcgis-map")?.view;

    // Configure popup docking
    if (view) {
      view.popup.dockEnabled = true;
      view.popup.dockOptions = {
        buttonEnabled: true,
        breakpoint: false,
        position: "top-left",
      };
    }

    set({
      mapElement: el,
      gallery,
      map,
      view,
    });
  },

  setMapLoaded: (value) =&amp;gt; set({ loading: value }),

  initBasemaps: () =&amp;gt; {
    const customBasemaps = Object.keys(basemapConfigs).map((key) =&amp;gt; {
      const config = basemapConfigs[key];
      const { url, title, type, minZoom, maxZoom } = config;

      let basemapLayer;

      // Define the class to add custom web tiles (mbtiles layer)
      const CustomMeckLayer = BaseTileLayer.createSubclass({
        properties: {
          urlTemplate: null,
        },
        // we need to match URL's structure /z/x/y to level/col/row
        getTileUrl: function (level, row, col) {
          return this.urlTemplate
            .replace("{z}", level)
            .replace("{x}", col)
            .replace("{y}", row);
        },
      });

      if (type === "custom_webtile") {
        basemapLayer = new CustomMeckLayer({
          // Pass the RAW string with placeholders here
          urlTemplate: config.url,
          title: title,
        });
        basemapLayer.minScale = 500000;
        basemapLayer.maxScale = 0;
      } else if (type === "webtile") {
        // WebTileLayer for XYZ/TMS tiles (e.g., mbtiles)
        basemapLayer = new WebTileLayer({
          urlTemplate: url,
          title,
          ...(minZoom !== undefined &amp;amp;&amp;amp; { minScale: getScaleFromZoom(minZoom) }),
          ...(maxZoom !== undefined &amp;amp;&amp;amp; { maxScale: getScaleFromZoom(maxZoom) }),
        });
      } else if (
        ["vectorbasemap", "vectorbasemapaerial", "vectorbasemapparks"].includes(
          key,
        )
      ) {
        basemapLayer = new MapImageLayer({ url, title });
      } else {
        basemapLayer = new TileLayer({ url, title });
      }
      return new Basemap({
        baseLayers: [basemapLayer],
        title,
        thumbnailUrl: config?.thumbnail,
      });
    });

    // Use gallery from mapElement
    const gallery = get().gallery;
    if (gallery &amp;amp;&amp;amp; customBasemaps.length &amp;gt; 0) {
      gallery.source = new LocalBasemapsSource({ basemaps: customBasemaps });
    }
    set({ basemap: customBasemaps[0] });
  },

  initMap: async () =&amp;gt; {
    const mapElement = get().mapElement;
    if (!mapElement) return;
    set({ loading: true });
    get().initBasemaps();
    set({
      loading: false, // loading done
    });
  },
}));&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;you can now directly use initMap function in your map component:&lt;/P&gt;&lt;LI-CODE lang="javascript"&gt;export default function MapViewer() {
  const { setMapElement, initMap, basemap } = useMapStore();

  useEffect(() =&amp;gt; {
    // We need to wait for &amp;lt;arcgis-map&amp;gt; to be in DOM
    const arcgisMapElem = document.querySelector("arcgis-map");
    if (!arcgisMapElem) return;

    // set ref into zustand store
    setMapElement(arcgisMapElem);

    // initialize basemap gallery and set default basemap
    initMap();
  }, [initMap, setMapElement]);


  return (
    &amp;lt;div className="w-full h-full relative"&amp;gt;
      &amp;lt;ArcgisMap
        className={mapConfig.initClass}
        basemap={basemap}
        center={mapConfig.initCenter}
        zoom={mapConfig.initZoom}
      &amp;gt;

        {/** Bottom Aligned Basemap Gallery */}
        &amp;lt;div
          className="fixed left-1/2 bottom-4 w-full transform -translate-x-1/2
                  bg-background/20 backdrop-blur-lg p-3
                  rounded-t-2xl shadow-lg"
        &amp;gt;
          &amp;lt;ArcgisBasemapGallery /&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/ArcgisMap&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
    <pubDate>Thu, 29 Jan 2026 19:47:46 GMT</pubDate>
    <dc:creator>kurtia</dc:creator>
    <dc:date>2026-01-29T19:47:46Z</dc:date>
    <item>
      <title>Basemap Gallery component - Add basemap from tile layer</title>
      <link>https://community.esri.com/t5/arcgis-javascript-maps-sdk-questions/basemap-gallery-component-add-basemap-from-tile/m-p/1674367#M87988</link>
      <description>&lt;P&gt;Does anyone have an example of how to remove the default basemaps in the basemap gallery component and add our own from a service layer.&amp;nbsp; I am struggling.&amp;nbsp; Thanks.&lt;/P&gt;</description>
      <pubDate>Fri, 19 Dec 2025 20:00:42 GMT</pubDate>
      <guid>https://community.esri.com/t5/arcgis-javascript-maps-sdk-questions/basemap-gallery-component-add-basemap-from-tile/m-p/1674367#M87988</guid>
      <dc:creator>MatthewDriscoll</dc:creator>
      <dc:date>2025-12-19T20:00:42Z</dc:date>
    </item>
    <item>
      <title>Re: Basemap Gallery component - Add basemap from tile layer</title>
      <link>https://community.esri.com/t5/arcgis-javascript-maps-sdk-questions/basemap-gallery-component-add-basemap-from-tile/m-p/1674395#M87989</link>
      <description>&lt;P&gt;Is this what you're referring to?&lt;/P&gt;&lt;P&gt;&lt;A href="https://www.esri.com/arcgis-blog/products/arcgis-online/mapping/custom-basemap-gallery" target="_blank"&gt;https://www.esri.com/arcgis-blog/products/arcgis-online/mapping/custom-basemap-gallery&lt;/A&gt;&lt;/P&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Fri, 19 Dec 2025 21:22:11 GMT</pubDate>
      <guid>https://community.esri.com/t5/arcgis-javascript-maps-sdk-questions/basemap-gallery-component-add-basemap-from-tile/m-p/1674395#M87989</guid>
      <dc:creator>Laura</dc:creator>
      <dc:date>2025-12-19T21:22:11Z</dc:date>
    </item>
    <item>
      <title>Re: Basemap Gallery component - Add basemap from tile layer</title>
      <link>https://community.esri.com/t5/arcgis-javascript-maps-sdk-questions/basemap-gallery-component-add-basemap-from-tile/m-p/1674397#M87990</link>
      <description>&lt;P&gt;No, not through online.&amp;nbsp; Using the SDK code.&amp;nbsp; Add the component in HTML and put it in a slot, then customize it in JS.&amp;nbsp; This the way the new format is supposed to go, no?&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="markup"&gt;    &amp;lt;!--Basemap Gallery--&amp;gt;
    &amp;lt;arcgis-basemap-gallery
        id="baseMapGal"
        slot="top-right"&amp;gt;
    &amp;lt;/arcgis-basemap-gallery&amp;gt;&lt;/LI-CODE&gt;&lt;LI-CODE lang="javascript"&gt;const basemapGallery = document.getElementById("baseMapGal");&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Fri, 19 Dec 2025 22:10:54 GMT</pubDate>
      <guid>https://community.esri.com/t5/arcgis-javascript-maps-sdk-questions/basemap-gallery-component-add-basemap-from-tile/m-p/1674397#M87990</guid>
      <dc:creator>MatthewDriscoll</dc:creator>
      <dc:date>2025-12-19T22:10:54Z</dc:date>
    </item>
    <item>
      <title>Re: Basemap Gallery component - Add basemap from tile layer</title>
      <link>https://community.esri.com/t5/arcgis-javascript-maps-sdk-questions/basemap-gallery-component-add-basemap-from-tile/m-p/1674428#M87993</link>
      <description>&lt;P&gt;I think I may have gotten it, or at least a working solution, by using the LocalBasemapsSources?&amp;nbsp; However the format/look is different.&amp;nbsp; So I am not sure.&amp;nbsp; Would still like to know if the actual basemap gallery component is a direction I can take.&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="javascript"&gt;let basemapGallery = new BasemapGallery({
 source: new LocalBasemapsSource({
   basemaps: [
     myBasemap//Basemap.fromId("topo-vector"), // create a basemap from a well known id basemap
   ]
  }),
 view: view
});
view.ui.add(basemapGallery, 'top-right');&lt;/LI-CODE&gt;&lt;P&gt;&lt;BR /&gt;&amp;nbsp;&lt;BR /&gt;&lt;BR /&gt;&lt;/P&gt;</description>
      <pubDate>Fri, 19 Dec 2025 23:23:55 GMT</pubDate>
      <guid>https://community.esri.com/t5/arcgis-javascript-maps-sdk-questions/basemap-gallery-component-add-basemap-from-tile/m-p/1674428#M87993</guid>
      <dc:creator>MatthewDriscoll</dc:creator>
      <dc:date>2025-12-19T23:23:55Z</dc:date>
    </item>
    <item>
      <title>Re: Basemap Gallery component - Add basemap from tile layer</title>
      <link>https://community.esri.com/t5/arcgis-javascript-maps-sdk-questions/basemap-gallery-component-add-basemap-from-tile/m-p/1674526#M87998</link>
      <description>&lt;P&gt;Hi&amp;nbsp;&lt;a href="https://community.esri.com/t5/user/viewprofilepage/user-id/327152"&gt;@MatthewDriscoll&lt;/a&gt;&amp;nbsp;- yes you can use the Basemap Gallery component to do this! Just set the source via JavaScript after adding the component to your markup. Example code snippet here -&amp;nbsp;&lt;A href="https://developers.arcgis.com/javascript/latest/references/map-components/arcgis-basemap-gallery/#source" target="_blank"&gt;https://developers.arcgis.com/javascript/latest/references/map-components/arcgis-basemap-gallery/#source&lt;/A&gt;&lt;/P&gt;</description>
      <pubDate>Mon, 22 Dec 2025 15:53:17 GMT</pubDate>
      <guid>https://community.esri.com/t5/arcgis-javascript-maps-sdk-questions/basemap-gallery-component-add-basemap-from-tile/m-p/1674526#M87998</guid>
      <dc:creator>AnneFitz</dc:creator>
      <dc:date>2025-12-22T15:53:17Z</dc:date>
    </item>
    <item>
      <title>Re: Basemap Gallery component - Add basemap from tile layer</title>
      <link>https://community.esri.com/t5/arcgis-javascript-maps-sdk-questions/basemap-gallery-component-add-basemap-from-tile/m-p/1680915#M88104</link>
      <description>&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;This is how I am adding custom basemaps gallery:&lt;/P&gt;&lt;LI-CODE lang="javascript"&gt;import { BASEPATH_URL_PATH } from "@/config/basepath.config";

export const basemapConfigs = {
    // WebTileLayer (XYZ/TMS tiles from mbtiles)
    customtiles: {
        id: 'custom-tiles',
        title: 'Custom Tiles',
        url: 'https://mydomain.com/mbtiles/custom.mbtiles/{z}/{x}/{y}',
        thumbnail: `${BASEPATH_URL_PATH}/basemaps/BasemapDefault.png`,
        type: 'custom_webtile', // indicates this is an XYZ/TMS tile layer
        minZoom: 9,
        maxZoom: 18,
    },
    // TileLayer
    default: {
        id: 'default',
        title: 'Basemap2',
        url: 'https://mydomain.com/server/rest/services/Basemap/Basemap/MapServer',
        thumbnail: `${BASEPATH_URL_PATH}/basemaps/BasemapDefault.png`,
    },
    // TileLayer
    aerial: {
        id: 'base-aerial',
        title: 'Aerial',
        url: 'https://mydomain.com/server/rest/services/Basemap/BasemapAerial/MapServer',
        thumbnail: `${BASEPATH_URL_PATH}/basemaps/BasemapAerial.png`,
    },
    // TileLayer
    grayscale: {
        id: 'grayscale',
        title: 'Grayscale',
        url: 'https://mydomain.com/server/rest/services/Basemap/BasemapGrayscale/MapServer',
        thumbnail: `${BASEPATH_URL_PATH}/basemaps/BasemapGrayscale.png`,
    },
    // TileLayer
    topohillshade: {
        id: 'topohillshade',
        title: 'TopoHillShade',
        url: 'https://mydomain.com/server/rest/services/Basemap/TopoHillShade/MapServer',
        thumbnail: `${BASEPATH_URL_PATH}/basemaps/TopoHillShade.png`,
    },
};&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;In map store:&amp;nbsp;&lt;/P&gt;&lt;LI-CODE lang="javascript"&gt;import { basemapConfigs } from "@/config/basemap.configs";
import Basemap from "@arcgis/core/Basemap";
import MapImageLayer from "@arcgis/core/layers/MapImageLayer";
import TileLayer from "@arcgis/core/layers/TileLayer";
import WebTileLayer from "@arcgis/core/layers/WebTileLayer";
import LocalBasemapsSource from "@arcgis/core/widgets/BasemapGallery/support/LocalBasemapsSource";
import { create } from "zustand";
import BaseTileLayer from "@arcgis/core/layers/BaseTileLayer";

/**
 * Helper function to convert zoom level to scale
 * Using Web Mercator scale approximation
 */
const getScaleFromZoom = (zoom) =&amp;gt; {
  const earthCircumference = 40075016.686; // meters
  const tileSize = 256;
  return earthCircumference / (tileSize * Math.pow(2, zoom));
};

export const useMapStore = create((set, get) =&amp;gt; ({
  mapElement: null,
  basemap: basemapConfigs.default,
  loading: true,
  map: null,
  view: null,
  gallery: null,

  setMapElement: (el) =&amp;gt; {
    const gallery = el?.querySelector("arcgis-basemap-gallery");
    const map = document.querySelector("arcgis-map")?.map;
    const view = document.querySelector("arcgis-map")?.view;

    // Configure popup docking
    if (view) {
      view.popup.dockEnabled = true;
      view.popup.dockOptions = {
        buttonEnabled: true,
        breakpoint: false,
        position: "top-left",
      };
    }

    set({
      mapElement: el,
      gallery,
      map,
      view,
    });
  },

  setMapLoaded: (value) =&amp;gt; set({ loading: value }),

  initBasemaps: () =&amp;gt; {
    const customBasemaps = Object.keys(basemapConfigs).map((key) =&amp;gt; {
      const config = basemapConfigs[key];
      const { url, title, type, minZoom, maxZoom } = config;

      let basemapLayer;

      // Define the class to add custom web tiles (mbtiles layer)
      const CustomMeckLayer = BaseTileLayer.createSubclass({
        properties: {
          urlTemplate: null,
        },
        // we need to match URL's structure /z/x/y to level/col/row
        getTileUrl: function (level, row, col) {
          return this.urlTemplate
            .replace("{z}", level)
            .replace("{x}", col)
            .replace("{y}", row);
        },
      });

      if (type === "custom_webtile") {
        basemapLayer = new CustomMeckLayer({
          // Pass the RAW string with placeholders here
          urlTemplate: config.url,
          title: title,
        });
        basemapLayer.minScale = 500000;
        basemapLayer.maxScale = 0;
      } else if (type === "webtile") {
        // WebTileLayer for XYZ/TMS tiles (e.g., mbtiles)
        basemapLayer = new WebTileLayer({
          urlTemplate: url,
          title,
          ...(minZoom !== undefined &amp;amp;&amp;amp; { minScale: getScaleFromZoom(minZoom) }),
          ...(maxZoom !== undefined &amp;amp;&amp;amp; { maxScale: getScaleFromZoom(maxZoom) }),
        });
      } else if (
        ["vectorbasemap", "vectorbasemapaerial", "vectorbasemapparks"].includes(
          key,
        )
      ) {
        basemapLayer = new MapImageLayer({ url, title });
      } else {
        basemapLayer = new TileLayer({ url, title });
      }
      return new Basemap({
        baseLayers: [basemapLayer],
        title,
        thumbnailUrl: config?.thumbnail,
      });
    });

    // Use gallery from mapElement
    const gallery = get().gallery;
    if (gallery &amp;amp;&amp;amp; customBasemaps.length &amp;gt; 0) {
      gallery.source = new LocalBasemapsSource({ basemaps: customBasemaps });
    }
    set({ basemap: customBasemaps[0] });
  },

  initMap: async () =&amp;gt; {
    const mapElement = get().mapElement;
    if (!mapElement) return;
    set({ loading: true });
    get().initBasemaps();
    set({
      loading: false, // loading done
    });
  },
}));&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;&lt;P&gt;you can now directly use initMap function in your map component:&lt;/P&gt;&lt;LI-CODE lang="javascript"&gt;export default function MapViewer() {
  const { setMapElement, initMap, basemap } = useMapStore();

  useEffect(() =&amp;gt; {
    // We need to wait for &amp;lt;arcgis-map&amp;gt; to be in DOM
    const arcgisMapElem = document.querySelector("arcgis-map");
    if (!arcgisMapElem) return;

    // set ref into zustand store
    setMapElement(arcgisMapElem);

    // initialize basemap gallery and set default basemap
    initMap();
  }, [initMap, setMapElement]);


  return (
    &amp;lt;div className="w-full h-full relative"&amp;gt;
      &amp;lt;ArcgisMap
        className={mapConfig.initClass}
        basemap={basemap}
        center={mapConfig.initCenter}
        zoom={mapConfig.initZoom}
      &amp;gt;

        {/** Bottom Aligned Basemap Gallery */}
        &amp;lt;div
          className="fixed left-1/2 bottom-4 w-full transform -translate-x-1/2
                  bg-background/20 backdrop-blur-lg p-3
                  rounded-t-2xl shadow-lg"
        &amp;gt;
          &amp;lt;ArcgisBasemapGallery /&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/ArcgisMap&amp;gt;
    &amp;lt;/div&amp;gt;
  );
}&lt;/LI-CODE&gt;&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Thu, 29 Jan 2026 19:47:46 GMT</pubDate>
      <guid>https://community.esri.com/t5/arcgis-javascript-maps-sdk-questions/basemap-gallery-component-add-basemap-from-tile/m-p/1680915#M88104</guid>
      <dc:creator>kurtia</dc:creator>
      <dc:date>2026-01-29T19:47:46Z</dc:date>
    </item>
  </channel>
</rss>

