AgentStack
SKILL verified MIT Self-run

Arcgis Widgets Ui

skill-saschabrunnerch-arcgis-maps-sdk-js-ai-context-arcgis-widgets-ui · by SaschaBrunnerCH

Build map user interfaces with ArcGIS widgets, Map Components, and Calcite Design System. Use for adding legends, layer lists, search, tables, time sliders, and custom UI layouts.

No reviews yet
0 installs
4 views
0.0% view→install

Install

$ agentstack add skill-saschabrunnerch-arcgis-maps-sdk-js-ai-context-arcgis-widgets-ui

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Arcgis Widgets Ui? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

ArcGIS Widgets & UI

Use this skill when building user interfaces with widgets, Map Components, and Calcite.

> Best Practice: Prefer Map Components (web components like arcgis-legend, arcgis-search) over Core API widgets. Esri has transitioned to web components as the primary approach.

Import Patterns

Map Components (ESM)

import "@arcgis/map-components/dist/components/arcgis-map";
import "@arcgis/map-components/dist/components/arcgis-legend";
import "@arcgis/map-components/dist/components/arcgis-search";
import "@arcgis/map-components/dist/components/arcgis-layer-list";
import "@arcgis/map-components/dist/components/arcgis-expand";

Core API Widgets (ESM)

import Legend from "@arcgis/core/widgets/Legend.js";
import LayerList from "@arcgis/core/widgets/LayerList.js";
import Search from "@arcgis/core/widgets/Search.js";
import BasemapGallery from "@arcgis/core/widgets/BasemapGallery.js";

Dynamic Imports (CDN)

const Legend = await $arcgis.import("@arcgis/core/widgets/Legend.js");
const Search = await $arcgis.import("@arcgis/core/widgets/Search.js");

> Note: CSS for Map Components loads automatically via npm. Core API widgets require: @import "@arcgis/core/assets/esri/themes/light/main.css";

Map Components Overview

| Component | Purpose | | ----------------------------------- | ---------------------------------- | | arcgis-map | 2D map container | | arcgis-scene | 3D scene container | | arcgis-zoom | Zoom in/out buttons | | arcgis-compass | Orientation indicator | | arcgis-home | Return to initial extent | | arcgis-locate | Find user location | | arcgis-track | Track user location | | arcgis-navigation-toggle | Pan/rotate mode (3D) | | arcgis-floor-filter | Filter indoor map by floor level | | arcgis-fullscreen | Toggle fullscreen | | arcgis-scale-bar | Display map scale | | arcgis-legend | Layer symbology legend | | arcgis-layer-list | Layer visibility control | | arcgis-basemap-gallery | Switch basemaps | | arcgis-basemap-layer-list | Layer list for basemap layers | | arcgis-basemap-toggle | Toggle two basemaps | | arcgis-catalog-layer-list | Browse CatalogLayer sublayers | | arcgis-search | Location search | | arcgis-placement | Control widget placement | | arcgis-popup | Feature popups | | arcgis-editor | Feature editing | | arcgis-feature | Display feature info without popup | | arcgis-feature-form | Form-based attribute editing | | arcgis-features | Display multiple features info | | arcgis-sketch | Draw geometries | | arcgis-feature-table | Tabular data view | | arcgis-time-slider | Temporal navigation | | arcgis-expand | Collapsible container | | arcgis-print | Map printing | | arcgis-table-list | List and manage feature tables | | arcgis-bookmarks | Navigate to bookmarks | | arcgis-directions | Turn-by-turn routing | | arcgis-swipe | Compare layers | | arcgis-coordinate-conversion | Coordinate formats | | arcgis-daylight | 3D lighting control | | arcgis-weather | 3D weather effects | | arcgis-distance-measurement-2d | 2D distance measurement | | arcgis-area-measurement-2d | 2D area measurement | | arcgis-direct-line-measurement-3d | 3D line measurement | | arcgis-area-measurement-3d | 3D area measurement | | arcgis-elevation-profile | Elevation profile along a path | | arcgis-line-of-sight | Line of sight analysis (3D) | | arcgis-slice | Slice through 3D data | | arcgis-shadow-cast | Shadow cast analysis (3D) | | arcgis-oriented-imagery-viewer | View oriented imagery | | arcgis-video-player | Play video feeds | | arcgis-link-chart | Link chart visualization | | arcgis-utility-network-trace | Utility network tracing | | arcgis-version-management | Manage geodatabase versions |

Slot-Based Positioning


  
  
  
  

  
  

  
  

  
  

Available slots: top-left, top-right, bottom-left, bottom-right, top-start, top-end, bottom-start, bottom-end, popup

Widgets in the same slot stack vertically in DOM order.

Expand Component

Wrap widgets in arcgis-expand for collapsible behavior:


  
    
  

  
    
  

Reference Element (External Components)

Place components outside the map and reference them:


  
    
  

  
    
  

Common Widgets

Legend

// Core API
import Legend from "@arcgis/core/widgets/Legend.js";

const legend = new Legend({
  view: view,
  layerInfos: [
    {
      layer: featureLayer,
      title: "Custom Title",
    },
  ],
});

view.ui.add(legend, "bottom-left");

LayerList

// Core API with actions
import LayerList from "@arcgis/core/widgets/LayerList.js";

const layerList = new LayerList({
  view: view,
  listItemCreatedFunction: (event) => {
    const item = event.item;
    item.actionsSections = [
      [
        {
          title: "Zoom to layer",
          icon: "zoom-to-object",
          id: "zoom-to",
        },
      ],
    ];
  },
});

layerList.on("trigger-action", (event) => {
  if (event.action.id === "zoom-to") {
    view.goTo(event.item.layer.fullExtent);
  }
});

view.ui.add(layerList, "top-right");

BasemapGallery

// Core API
import BasemapGallery from "@arcgis/core/widgets/BasemapGallery.js";

const basemapGallery = new BasemapGallery({ view: view });
view.ui.add(basemapGallery, "top-right");

Search

// Core API with custom sources
import Search from "@arcgis/core/widgets/Search.js";

const search = new Search({
  view: view,
  sources: [
    {
      layer: featureLayer,
      searchFields: ["name", "address"],
      displayField: "name",
      exactMatch: false,
      outFields: ["*"],
      name: "My Layer",
      placeholder: "Search features",
    },
  ],
});

view.ui.add(search, "top-right");

// Events
search.on("select-result", (event) => {
  console.log("Selected:", event.result);
});

FeatureTable

// Core API
import FeatureTable from "@arcgis/core/widgets/FeatureTable.js";

const featureTable = new FeatureTable({
  view: view,
  layer: featureLayer,
  container: "tableDiv",
  visibleElements: {
    header: true,
    columnMenus: true,
    selectionColumn: true,
  },
  tableTemplate: {
    columnTemplates: [
      { fieldName: "name", label: "Name" },
      { fieldName: "population", label: "Population" },
    ],
  },
});

// Watch selection via highlightIds
featureTable.highlightIds.on("change", (event) => {
  console.log("Selected IDs:", featureTable.highlightIds.toArray());
});

TimeSlider


  const timeSlider = document.querySelector("arcgis-time-slider");
  const mapEl = document.querySelector("arcgis-map");
  await mapEl.viewOnReady();

  await layer.load();
  timeSlider.fullTimeExtent = layer.timeInfo.fullTimeExtent;
  timeSlider.stops = { interval: layer.timeInfo.interval };
// Core API
import TimeSlider from "@arcgis/core/widgets/TimeSlider.js";

const timeSlider = new TimeSlider({
  view: view,
  mode: "time-window", // instant, time-window, cumulative-from-start, cumulative-from-end
  fullTimeExtent: layer.timeInfo.fullTimeExtent,
  stops: {
    interval: { value: 1, unit: "hours" },
  },
  playRate: 1000,
  loop: true,
});

view.ui.add(timeSlider, "bottom-right");

// Events
import * as reactiveUtils from "@arcgis/core/core/reactiveUtils.js";

reactiveUtils.watch(
  () => timeSlider.timeExtent,
  (timeExtent) => {
    console.log("Time changed:", timeExtent.start, timeExtent.end);
  },
);

Core Widget Approach

Adding Widgets to View

import Legend from "@arcgis/core/widgets/Legend.js";

const legend = new Legend({ view: view });

// Add to view UI
view.ui.add(legend, "bottom-left");

// Add multiple widgets
view.ui.add([
  { component: legend, position: "bottom-left" },
  { component: search, position: "top-right" },
]);

// Add at specific index (order in position)
view.ui.add(legend, { position: "bottom-left", index: 0 });

// Remove widget
view.ui.remove(legend);

Widget in Custom Container


  import Legend from "@arcgis/core/widgets/Legend.js";

  const legend = new Legend({
    view: view,
    container: "legendDiv",
  });

Calcite Design System Integration

Basic Layout with Calcite


  
    
    
    
    
      html,
      body {
        height: 100%;
        margin: 0;
      }
    
  
  
    
      
      
        
      

      
      
        
          
        
      

      
      
        
      

      
      
        
          
        
      
    
  

Calcite Action Bar


  
    
      
      
      
    

    
      
    

    
      
    
  

  

  document.querySelectorAll("calcite-action").forEach((action) => {
    action.addEventListener("click", () => {
      const panelId = action.dataset.panel;
      document.querySelectorAll("calcite-panel").forEach((panel) => {
        panel.hidden = panel.id !== panelId;
      });
    });
  });

Common Calcite Components

| Component | Purpose | | --------------------- | -------------------- | | calcite-shell | App layout container | | calcite-shell-panel | Side panels | | calcite-panel | Content panel | | calcite-navigation | Header/footer | | calcite-action-bar | Icon button bar | | calcite-action | Icon button | | calcite-button | Standard button | | calcite-input | Text input | | calcite-list | List container | | calcite-list-item | List item | | calcite-card | Card container | | calcite-modal | Modal dialog | | calcite-alert | Alert message | | calcite-loader | Loading indicator |

Theming


  
  
    
    
      :root {
        --calcite-color-brand: #007ac2;
        --calcite-color-brand-hover: #005a8e;
        --calcite-color-text-1: #323232;
      }
    
  

Widget Events

// Search select
search.on("select-result", (event) => {
  console.log(event.result);
});

// LayerList trigger action
layerList.on("trigger-action", (event) => {
  console.log(event.action, event.item);
});

// FeatureTable selection
featureTable.highlightIds.on("change", (event) => {
  console.log(event.added, event.removed);
});

Reference Samples

  • legend - Legend widget for layer symbology
  • widgets-layerlist - LayerList widget for layer management
  • widgets-search-multiplesource - Search widget with multiple sources
  • widgets-featuretable - FeatureTable widget integration
  • basemap-gallery - BasemapGallery for switching basemaps
  • widgets-timeslider - TimeSlider widget for temporal data

Common Pitfalls

  1. Missing reference-element: Components placed outside the `` tag cannot find the view without an explicit reference.

```html

```

```html

```

Impact: The component cannot discover the associated view. It either does not render or throws an error.

  1. Slot names are specific: Use exact slot names (top-left, not topleft).
  1. Calcite CSS not loading: Ensure Calcite script is loaded before using Calcite components.
  1. Widget container conflicts: Do not add the same widget to both a DOM container and view.ui.

``javascript // Anti-pattern: widget in both container and view.ui const legend = new Legend({ view: view, container: "legendDiv" }); view.ui.add(legend, "bottom-right"); // Conflicts ``

``javascript // Correct: pick one placement strategy const legend = new Legend({ view: view }); view.ui.add(legend, "bottom-right"); ``

Impact: The widget renders twice or the layout breaks.

  1. Dark/light mode mismatch: Add calcite-mode-light or calcite-mode-dark class to body.
  1. Core API widgets missing CSS: When using Core API widgets (not Map Components), you must import @arcgis/core/assets/esri/themes/light/main.css. Map Components handle CSS automatically.

Related Skills

  • See arcgis-widgets-advanced for specialized widgets (BuildingExplorer, FloorFilter, Track, Locate, etc.)
  • See arcgis-map-tools for measurement, print, directions, and swipe tools
  • See arcgis-editing for Editor and Sketch widgets
  • See arcgis-tables-forms for FeatureTable and FeatureForm details

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.