@saschabrunnerch/arcgis-maps-sdk-js-ai-context 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +163 -201
  2. package/bin/cli.js +157 -173
  3. package/contexts/4.34/{claude → skills}/arcgis-3d-advanced/SKILL.md +586 -586
  4. package/contexts/4.34/{claude → skills}/arcgis-advanced-layers/SKILL.md +431 -431
  5. package/contexts/4.34/{claude → skills}/arcgis-analysis-services/SKILL.md +607 -607
  6. package/contexts/4.34/{claude → skills}/arcgis-authentication/SKILL.md +301 -301
  7. package/contexts/4.34/{claude → skills}/arcgis-cim-symbols/SKILL.md +486 -486
  8. package/contexts/4.34/{claude → skills}/arcgis-coordinates-projection/SKILL.md +406 -406
  9. package/contexts/4.34/{claude → skills}/arcgis-core-maps/SKILL.md +739 -739
  10. package/contexts/4.34/{claude → skills}/arcgis-core-utilities/SKILL.md +732 -732
  11. package/contexts/4.34/{claude → skills}/arcgis-custom-rendering/SKILL.md +445 -445
  12. package/contexts/4.34/{claude → skills}/arcgis-editing-advanced/SKILL.md +702 -702
  13. package/contexts/4.34/{claude → skills}/arcgis-feature-effects/SKILL.md +393 -393
  14. package/contexts/4.34/{claude → skills}/arcgis-geometry-operations/SKILL.md +489 -489
  15. package/contexts/4.34/{claude → skills}/arcgis-imagery/SKILL.md +307 -307
  16. package/contexts/4.34/{claude → skills}/arcgis-interaction/SKILL.md +572 -572
  17. package/contexts/4.34/{claude → skills}/arcgis-knowledge-graphs/SKILL.md +582 -582
  18. package/contexts/4.34/{claude → skills}/arcgis-layers/SKILL.md +601 -601
  19. package/contexts/4.34/{claude → skills}/arcgis-map-tools/SKILL.md +668 -668
  20. package/contexts/4.34/{claude → skills}/arcgis-media-layers/SKILL.md +290 -290
  21. package/contexts/4.34/{claude → skills}/arcgis-portal-content/SKILL.md +679 -679
  22. package/contexts/4.34/{claude → skills}/arcgis-scene-effects/SKILL.md +512 -512
  23. package/contexts/4.34/{claude → skills}/arcgis-smart-mapping/SKILL.md +686 -686
  24. package/contexts/4.34/skills/arcgis-starter-app/SKILL.md +273 -0
  25. package/contexts/4.34/skills/arcgis-starter-app-extended/SKILL.md +649 -0
  26. package/contexts/4.34/{claude → skills}/arcgis-tables-forms/SKILL.md +877 -877
  27. package/contexts/4.34/{claude → skills}/arcgis-time-animation/SKILL.md +722 -722
  28. package/contexts/4.34/{claude → skills}/arcgis-utility-networks/SKILL.md +301 -301
  29. package/contexts/4.34/{claude → skills}/arcgis-visualization/SKILL.md +580 -580
  30. package/contexts/4.34/{claude → skills}/arcgis-widgets-ui/SKILL.md +574 -574
  31. package/lib/installer.js +294 -379
  32. package/package.json +45 -45
  33. package/contexts/4.34/copilot/arcgis-3d.instructions.md +0 -267
  34. package/contexts/4.34/copilot/arcgis-analysis.instructions.md +0 -294
  35. package/contexts/4.34/copilot/arcgis-arcade.instructions.md +0 -234
  36. package/contexts/4.34/copilot/arcgis-authentication.instructions.md +0 -187
  37. package/contexts/4.34/copilot/arcgis-cim-symbols.instructions.md +0 -177
  38. package/contexts/4.34/copilot/arcgis-core-maps.instructions.md +0 -246
  39. package/contexts/4.34/copilot/arcgis-core-utilities.instructions.md +0 -247
  40. package/contexts/4.34/copilot/arcgis-editing.instructions.md +0 -262
  41. package/contexts/4.34/copilot/arcgis-geometry.instructions.md +0 -225
  42. package/contexts/4.34/copilot/arcgis-layers.instructions.md +0 -278
  43. package/contexts/4.34/copilot/arcgis-popup-templates.instructions.md +0 -266
  44. package/contexts/4.34/copilot/arcgis-portal-advanced.instructions.md +0 -275
  45. package/contexts/4.34/copilot/arcgis-smart-mapping.instructions.md +0 -184
  46. package/contexts/4.34/copilot/arcgis-time-animation.instructions.md +0 -112
  47. package/contexts/4.34/copilot/arcgis-visualization.instructions.md +0 -321
  48. package/contexts/4.34/copilot/arcgis-widgets-ui.instructions.md +0 -277
  49. /package/contexts/4.34/{claude → skills}/arcgis-arcade/SKILL.md +0 -0
  50. /package/contexts/4.34/{claude → skills}/arcgis-popup-templates/SKILL.md +0 -0
@@ -1,574 +1,574 @@
1
- ---
2
- name: arcgis-widgets-ui
3
- description: 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.
4
- ---
5
-
6
- # ArcGIS Widgets & UI
7
-
8
- Use this skill when building user interfaces with widgets, Map Components, and Calcite.
9
-
10
- > **Best Practice:** Prefer Map Components (web components like `arcgis-legend`, `arcgis-search`) over Core API widgets when possible. Esri is transitioning to web components, and some widgets are already deprecated. See [Esri's component transition plan](https://developers.arcgis.com/javascript/latest/components-transition-plan/).
11
-
12
- ## Map Components Approach
13
-
14
- ### Available Map Components
15
-
16
- | Component | Purpose |
17
- |-----------|---------|
18
- | `arcgis-map` | 2D map container |
19
- | `arcgis-scene` | 3D scene container |
20
- | `arcgis-zoom` | Zoom in/out buttons |
21
- | `arcgis-compass` | Orientation indicator |
22
- | `arcgis-home` | Return to initial extent |
23
- | `arcgis-locate` | Find user location |
24
- | `arcgis-track` | Track user location |
25
- | `arcgis-navigation-toggle` | Pan/rotate mode (3D) |
26
- | `arcgis-fullscreen` | Toggle fullscreen |
27
- | `arcgis-scale-bar` | Display map scale |
28
- | `arcgis-legend` | Layer symbology legend |
29
- | `arcgis-layer-list` | Layer visibility control |
30
- | `arcgis-basemap-gallery` | Switch basemaps |
31
- | `arcgis-basemap-toggle` | Toggle two basemaps |
32
- | `arcgis-search` | Location search |
33
- | `arcgis-popup` | Feature popups |
34
- | `arcgis-editor` | Feature editing |
35
- | `arcgis-sketch` | Draw geometries |
36
- | `arcgis-feature-table` | Tabular data view |
37
- | `arcgis-time-slider` | Temporal navigation |
38
- | `arcgis-time-zone-label` | Display time zone |
39
- | `arcgis-expand` | Collapsible container |
40
- | `arcgis-print` | Map printing |
41
- | `arcgis-bookmarks` | Navigate to bookmarks |
42
- | `arcgis-directions` | Turn-by-turn routing |
43
- | `arcgis-swipe` | Compare layers |
44
- | `arcgis-coordinate-conversion` | Coordinate formats |
45
- | `arcgis-daylight` | 3D lighting control |
46
- | `arcgis-weather` | 3D weather effects |
47
- | `arcgis-distance-measurement-2d` | 2D distance measurement |
48
- | `arcgis-area-measurement-2d` | 2D area measurement |
49
- | `arcgis-direct-line-measurement-3d` | 3D line measurement |
50
- | `arcgis-area-measurement-3d` | 3D area measurement |
51
- | `arcgis-utility-network-trace` | Utility network tracing |
52
- | `arcgis-utility-network-associations` | Utility associations |
53
-
54
- > **Note:** Not all widgets have component equivalents yet. FeatureForm, Histogram, and some specialized widgets only have Core API versions.
55
-
56
- ### Slot-Based Positioning
57
-
58
- ```html
59
- <arcgis-map basemap="streets-vector">
60
- <!-- Position widgets using slots -->
61
- <arcgis-zoom slot="top-left"></arcgis-zoom>
62
- <arcgis-home slot="top-left"></arcgis-home>
63
- <arcgis-compass slot="top-left"></arcgis-compass>
64
-
65
- <arcgis-search slot="top-right"></arcgis-search>
66
- <arcgis-layer-list slot="top-right"></arcgis-layer-list>
67
-
68
- <arcgis-legend slot="bottom-left"></arcgis-legend>
69
- <arcgis-scale-bar slot="bottom-right"></arcgis-scale-bar>
70
-
71
- <!-- Popup must use popup slot -->
72
- <arcgis-popup slot="popup"></arcgis-popup>
73
- </arcgis-map>
74
- ```
75
-
76
- Available slots: `top-left`, `top-right`, `bottom-left`, `bottom-right`, `popup`, `manual`
77
-
78
- ### Expand Component
79
-
80
- Wrap widgets in `arcgis-expand` for collapsible behavior:
81
-
82
- ```html
83
- <arcgis-map basemap="streets-vector">
84
- <arcgis-expand slot="top-right" expand-tooltip="Show Legend" mode="floating">
85
- <arcgis-legend></arcgis-legend>
86
- </arcgis-expand>
87
-
88
- <arcgis-expand slot="top-left" expanded>
89
- <arcgis-layer-list></arcgis-layer-list>
90
- </arcgis-expand>
91
- </arcgis-map>
92
- ```
93
-
94
- ### Reference Element (External Components)
95
-
96
- Place components outside the map and reference them:
97
-
98
- ```html
99
- <calcite-shell>
100
- <calcite-shell-panel slot="panel-start">
101
- <arcgis-legend reference-element="arcgis-map"></arcgis-legend>
102
- </calcite-shell-panel>
103
-
104
- <arcgis-map id="arcgis-map" basemap="topo-vector">
105
- <arcgis-zoom slot="top-left"></arcgis-zoom>
106
- </arcgis-map>
107
- </calcite-shell>
108
- ```
109
-
110
- ## Core Widget Approach
111
-
112
- ### Adding Widgets to View
113
-
114
- ```javascript
115
- import Legend from "@arcgis/core/widgets/Legend.js";
116
- import LayerList from "@arcgis/core/widgets/LayerList.js";
117
- import Search from "@arcgis/core/widgets/Search.js";
118
-
119
- // Create widget
120
- const legend = new Legend({ view: view });
121
-
122
- // Add to view UI
123
- view.ui.add(legend, "bottom-left");
124
-
125
- // Add multiple widgets
126
- view.ui.add([
127
- { component: legend, position: "bottom-left" },
128
- { component: search, position: "top-right" }
129
- ]);
130
-
131
- // Add to specific index (order in position)
132
- view.ui.add(legend, { position: "bottom-left", index: 0 });
133
-
134
- // Remove widget
135
- view.ui.remove(legend);
136
- ```
137
-
138
- ### Widget in Custom Container
139
-
140
- ```html
141
- <div id="legendDiv"></div>
142
-
143
- <script type="module">
144
- import Legend from "@arcgis/core/widgets/Legend.js";
145
-
146
- const legend = new Legend({
147
- view: view,
148
- container: "legendDiv" // Or document.getElementById("legendDiv")
149
- });
150
- </script>
151
- ```
152
-
153
- ## Common Widgets
154
-
155
- ### Legend
156
-
157
- ```html
158
- <!-- Map Component -->
159
- <arcgis-legend slot="bottom-left"></arcgis-legend>
160
- ```
161
-
162
- ```javascript
163
- // Core API
164
- import Legend from "@arcgis/core/widgets/Legend.js";
165
-
166
- const legend = new Legend({
167
- view: view,
168
- layerInfos: [{
169
- layer: featureLayer,
170
- title: "Custom Title"
171
- }]
172
- });
173
-
174
- view.ui.add(legend, "bottom-left");
175
- ```
176
-
177
- ### LayerList
178
-
179
- ```html
180
- <!-- Map Component -->
181
- <arcgis-layer-list slot="top-right"></arcgis-layer-list>
182
- ```
183
-
184
- ```javascript
185
- // Core API with actions
186
- import LayerList from "@arcgis/core/widgets/LayerList.js";
187
-
188
- const layerList = new LayerList({
189
- view: view,
190
- listItemCreatedFunction: (event) => {
191
- const item = event.item;
192
- item.actionsSections = [[{
193
- title: "Zoom to layer",
194
- icon: "zoom-to-object",
195
- id: "zoom-to"
196
- }]];
197
- }
198
- });
199
-
200
- layerList.on("trigger-action", (event) => {
201
- if (event.action.id === "zoom-to") {
202
- view.goTo(event.item.layer.fullExtent);
203
- }
204
- });
205
-
206
- view.ui.add(layerList, "top-right");
207
- ```
208
-
209
- ### BasemapGallery
210
-
211
- ```html
212
- <!-- Map Component -->
213
- <arcgis-basemap-gallery slot="top-right"></arcgis-basemap-gallery>
214
- ```
215
-
216
- ```javascript
217
- // Core API
218
- import BasemapGallery from "@arcgis/core/widgets/BasemapGallery.js";
219
-
220
- const basemapGallery = new BasemapGallery({
221
- view: view
222
- });
223
-
224
- view.ui.add(basemapGallery, "top-right");
225
- ```
226
-
227
- ### Search
228
-
229
- ```html
230
- <!-- Map Component -->
231
- <arcgis-search slot="top-right"></arcgis-search>
232
- ```
233
-
234
- ```javascript
235
- // Core API with custom sources
236
- import Search from "@arcgis/core/widgets/Search.js";
237
-
238
- const search = new Search({
239
- view: view,
240
- sources: [{
241
- layer: featureLayer,
242
- searchFields: ["name", "address"],
243
- displayField: "name",
244
- exactMatch: false,
245
- outFields: ["*"],
246
- name: "My Layer",
247
- placeholder: "Search features"
248
- }]
249
- });
250
-
251
- view.ui.add(search, "top-right");
252
-
253
- // Events
254
- search.on("select-result", (event) => {
255
- console.log("Selected:", event.result);
256
- });
257
- ```
258
-
259
- ### FeatureTable
260
-
261
- ```html
262
- <!-- Map Component -->
263
- <arcgis-feature-table reference-element="arcgis-map"></arcgis-feature-table>
264
- ```
265
-
266
- ```javascript
267
- // Core API
268
- import FeatureTable from "@arcgis/core/widgets/FeatureTable.js";
269
-
270
- const featureTable = new FeatureTable({
271
- view: view,
272
- layer: featureLayer,
273
- container: "tableDiv",
274
- visibleElements: {
275
- header: true,
276
- columnMenus: true,
277
- selectionColumn: true
278
- },
279
- fieldConfigs: [
280
- { name: "name", label: "Name" },
281
- { name: "population", label: "Population" }
282
- ]
283
- });
284
-
285
- // Selection events
286
- featureTable.on("selection-change", (event) => {
287
- console.log("Selected rows:", event.added);
288
- });
289
- ```
290
-
291
- ### TimeSlider
292
-
293
- ```html
294
- <!-- Map Component -->
295
- <arcgis-time-slider
296
- slot="bottom-right"
297
- layout="auto"
298
- mode="time-window"
299
- time-visible
300
- loop>
301
- </arcgis-time-slider>
302
-
303
- <script type="module">
304
- const timeSlider = document.querySelector("arcgis-time-slider");
305
- await layer.load();
306
-
307
- timeSlider.fullTimeExtent = layer.timeInfo.fullTimeExtent;
308
- timeSlider.stops = {
309
- interval: layer.timeInfo.interval
310
- };
311
- </script>
312
- ```
313
-
314
- ```javascript
315
- // Core API
316
- import TimeSlider from "@arcgis/core/widgets/TimeSlider.js";
317
-
318
- const timeSlider = new TimeSlider({
319
- view: view,
320
- mode: "time-window", // instant, time-window, cumulative-from-start, cumulative-from-end
321
- fullTimeExtent: layer.timeInfo.fullTimeExtent,
322
- stops: {
323
- interval: {
324
- value: 1,
325
- unit: "hours"
326
- }
327
- },
328
- playRate: 1000, // ms between stops
329
- loop: true
330
- });
331
-
332
- view.ui.add(timeSlider, "bottom-right");
333
-
334
- // Events
335
- timeSlider.watch("timeExtent", (timeExtent) => {
336
- console.log("Time changed:", timeExtent.start, timeExtent.end);
337
- });
338
- ```
339
-
340
- ### Print
341
-
342
- ```html
343
- <!-- Map Component -->
344
- <arcgis-print slot="top-right"></arcgis-print>
345
- ```
346
-
347
- ```javascript
348
- // Core API
349
- import Print from "@arcgis/core/widgets/Print.js";
350
-
351
- const print = new Print({
352
- view: view,
353
- printServiceUrl: "https://utility.arcgisonline.com/arcgis/rest/services/Utilities/PrintingTools/GPServer/Export%20Web%20Map%20Task"
354
- });
355
-
356
- view.ui.add(print, "top-right");
357
- ```
358
-
359
- ## Calcite Design System Integration
360
-
361
- ### Basic Layout with Calcite
362
-
363
- ```html
364
- <!DOCTYPE html>
365
- <html>
366
- <head>
367
- <script type="module" src="https://js.arcgis.com/calcite-components/3.3.3/calcite.esm.js"></script>
368
- <script src="https://js.arcgis.com/4.34/"></script>
369
- <script type="module" src="https://js.arcgis.com/4.34/map-components/"></script>
370
- <style>
371
- html, body { height: 100%; margin: 0; }
372
- </style>
373
- </head>
374
- <body class="calcite-mode-light">
375
- <calcite-shell>
376
- <!-- Header -->
377
- <calcite-navigation slot="header">
378
- <calcite-navigation-logo slot="logo" heading="My Map App"></calcite-navigation-logo>
379
- </calcite-navigation>
380
-
381
- <!-- Side Panel -->
382
- <calcite-shell-panel slot="panel-start">
383
- <calcite-panel heading="Layers">
384
- <arcgis-layer-list reference-element="map"></arcgis-layer-list>
385
- </calcite-panel>
386
- </calcite-shell-panel>
387
-
388
- <!-- Map -->
389
- <arcgis-map id="map" basemap="streets-vector">
390
- <arcgis-zoom slot="top-left"></arcgis-zoom>
391
- </arcgis-map>
392
-
393
- <!-- End Panel -->
394
- <calcite-shell-panel slot="panel-end">
395
- <calcite-panel heading="Legend">
396
- <arcgis-legend reference-element="map"></arcgis-legend>
397
- </calcite-panel>
398
- </calcite-shell-panel>
399
- </calcite-shell>
400
- </body>
401
- </html>
402
- ```
403
-
404
- ### Calcite Action Bar
405
-
406
- ```html
407
- <calcite-shell>
408
- <calcite-shell-panel slot="panel-start">
409
- <calcite-action-bar slot="action-bar">
410
- <calcite-action icon="layers" text="Layers" data-panel="layers"></calcite-action>
411
- <calcite-action icon="legend" text="Legend" data-panel="legend"></calcite-action>
412
- <calcite-action icon="bookmark" text="Bookmarks" data-panel="bookmarks"></calcite-action>
413
- </calcite-action-bar>
414
-
415
- <calcite-panel id="layers" heading="Layers">
416
- <arcgis-layer-list reference-element="map"></arcgis-layer-list>
417
- </calcite-panel>
418
-
419
- <calcite-panel id="legend" heading="Legend" hidden>
420
- <arcgis-legend reference-element="map"></arcgis-legend>
421
- </calcite-panel>
422
- </calcite-shell-panel>
423
-
424
- <arcgis-map id="map" basemap="topo-vector"></arcgis-map>
425
- </calcite-shell>
426
-
427
- <script>
428
- // Toggle panels on action click
429
- document.querySelectorAll("calcite-action").forEach(action => {
430
- action.addEventListener("click", () => {
431
- const panelId = action.dataset.panel;
432
- document.querySelectorAll("calcite-panel").forEach(panel => {
433
- panel.hidden = panel.id !== panelId;
434
- });
435
- });
436
- });
437
- </script>
438
- ```
439
-
440
- ### Common Calcite Components
441
-
442
- | Component | Purpose |
443
- |-----------|---------|
444
- | `calcite-shell` | App layout container |
445
- | `calcite-shell-panel` | Side panels |
446
- | `calcite-panel` | Content panel |
447
- | `calcite-navigation` | Header/footer |
448
- | `calcite-action-bar` | Icon button bar |
449
- | `calcite-action` | Icon button |
450
- | `calcite-button` | Standard button |
451
- | `calcite-input` | Text input |
452
- | `calcite-list` | List container |
453
- | `calcite-list-item` | List item |
454
- | `calcite-card` | Card container |
455
- | `calcite-modal` | Modal dialog |
456
- | `calcite-alert` | Alert message |
457
- | `calcite-loader` | Loading indicator |
458
-
459
- ### Theming
460
-
461
- ```html
462
- <!-- Light mode -->
463
- <body class="calcite-mode-light">
464
-
465
- <!-- Dark mode -->
466
- <body class="calcite-mode-dark">
467
-
468
- <!-- Custom theme colors -->
469
- <style>
470
- :root {
471
- --calcite-color-brand: #007ac2;
472
- --calcite-color-brand-hover: #005a8e;
473
- --calcite-color-text-1: #323232;
474
- }
475
- </style>
476
- ```
477
-
478
- ## Custom Widget Placement
479
-
480
- ### Manual Positioning
481
-
482
- ```javascript
483
- // Add widget at specific position
484
- view.ui.add(widget, {
485
- position: "manual",
486
- index: 0
487
- });
488
-
489
- // Position with CSS
490
- document.getElementById("myWidget").style.cssText = `
491
- position: absolute;
492
- top: 10px;
493
- left: 50%;
494
- transform: translateX(-50%);
495
- `;
496
- ```
497
-
498
- ### DOM Container
499
-
500
- ```html
501
- <div id="mapDiv" style="position: relative;">
502
- <div id="customWidget" style="position: absolute; top: 10px; right: 10px; z-index: 1;">
503
- <!-- Custom content -->
504
- </div>
505
- </div>
506
- ```
507
-
508
- ## Widget Events
509
-
510
- ```javascript
511
- // Search select
512
- search.on("select-result", (event) => {
513
- console.log(event.result);
514
- });
515
-
516
- // LayerList trigger action
517
- layerList.on("trigger-action", (event) => {
518
- console.log(event.action, event.item);
519
- });
520
-
521
- // TimeSlider time change
522
- timeSlider.watch("timeExtent", (value) => {
523
- console.log(value.start, value.end);
524
- });
525
-
526
- // FeatureTable selection
527
- featureTable.on("selection-change", (event) => {
528
- console.log(event.added, event.removed);
529
- });
530
- ```
531
-
532
- ## TypeScript Usage
533
-
534
- Widget configurations use autocasting with `type` properties. For TypeScript safety, use `as const`:
535
-
536
- ```typescript
537
- // Use 'as const' for widget configurations
538
- const layerList = new LayerList({
539
- view: view,
540
- listItemCreatedFunction: (event) => {
541
- const item = event.item;
542
- item.actionsSections = [[{
543
- title: "Zoom to layer",
544
- icon: "zoom-to-object",
545
- id: "zoom-to"
546
- }]];
547
- }
548
- });
549
-
550
- // For layer configurations in widgets
551
- const featureTable = new FeatureTable({
552
- view: view,
553
- layer: featureLayer,
554
- fieldConfigs: [
555
- { name: "name", label: "Name" },
556
- { name: "population", label: "Population" }
557
- ]
558
- });
559
- ```
560
-
561
- > **Tip:** See [arcgis-core-maps skill](../arcgis-core-maps/SKILL.md) for detailed guidance on autocasting vs explicit classes.
562
-
563
- ## Common Pitfalls
564
-
565
- 1. **Missing reference-element**: When placing components outside the map, use `reference-element` attribute
566
-
567
- 2. **Slot names are specific**: Use exact slot names (`top-left`, not `topleft`)
568
-
569
- 3. **Calcite CSS not loading**: Ensure Calcite script is loaded before using Calcite components
570
-
571
- 4. **Widget container conflicts**: Don't add the same widget to both a container and view.ui
572
-
573
- 5. **Dark/light mode mismatch**: Add `calcite-mode-light` or `calcite-mode-dark` class to body
574
-
1
+ ---
2
+ name: arcgis-widgets-ui
3
+ description: 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.
4
+ ---
5
+
6
+ # ArcGIS Widgets & UI
7
+
8
+ Use this skill when building user interfaces with widgets, Map Components, and Calcite.
9
+
10
+ > **Best Practice:** Prefer Map Components (web components like `arcgis-legend`, `arcgis-search`) over Core API widgets when possible. Esri is transitioning to web components, and some widgets are already deprecated. See [Esri's component transition plan](https://developers.arcgis.com/javascript/latest/components-transition-plan/).
11
+
12
+ ## Map Components Approach
13
+
14
+ ### Available Map Components
15
+
16
+ | Component | Purpose |
17
+ |-----------|---------|
18
+ | `arcgis-map` | 2D map container |
19
+ | `arcgis-scene` | 3D scene container |
20
+ | `arcgis-zoom` | Zoom in/out buttons |
21
+ | `arcgis-compass` | Orientation indicator |
22
+ | `arcgis-home` | Return to initial extent |
23
+ | `arcgis-locate` | Find user location |
24
+ | `arcgis-track` | Track user location |
25
+ | `arcgis-navigation-toggle` | Pan/rotate mode (3D) |
26
+ | `arcgis-fullscreen` | Toggle fullscreen |
27
+ | `arcgis-scale-bar` | Display map scale |
28
+ | `arcgis-legend` | Layer symbology legend |
29
+ | `arcgis-layer-list` | Layer visibility control |
30
+ | `arcgis-basemap-gallery` | Switch basemaps |
31
+ | `arcgis-basemap-toggle` | Toggle two basemaps |
32
+ | `arcgis-search` | Location search |
33
+ | `arcgis-popup` | Feature popups |
34
+ | `arcgis-editor` | Feature editing |
35
+ | `arcgis-sketch` | Draw geometries |
36
+ | `arcgis-feature-table` | Tabular data view |
37
+ | `arcgis-time-slider` | Temporal navigation |
38
+ | `arcgis-time-zone-label` | Display time zone |
39
+ | `arcgis-expand` | Collapsible container |
40
+ | `arcgis-print` | Map printing |
41
+ | `arcgis-bookmarks` | Navigate to bookmarks |
42
+ | `arcgis-directions` | Turn-by-turn routing |
43
+ | `arcgis-swipe` | Compare layers |
44
+ | `arcgis-coordinate-conversion` | Coordinate formats |
45
+ | `arcgis-daylight` | 3D lighting control |
46
+ | `arcgis-weather` | 3D weather effects |
47
+ | `arcgis-distance-measurement-2d` | 2D distance measurement |
48
+ | `arcgis-area-measurement-2d` | 2D area measurement |
49
+ | `arcgis-direct-line-measurement-3d` | 3D line measurement |
50
+ | `arcgis-area-measurement-3d` | 3D area measurement |
51
+ | `arcgis-utility-network-trace` | Utility network tracing |
52
+ | `arcgis-utility-network-associations` | Utility associations |
53
+
54
+ > **Note:** Not all widgets have component equivalents yet. FeatureForm, Histogram, and some specialized widgets only have Core API versions.
55
+
56
+ ### Slot-Based Positioning
57
+
58
+ ```html
59
+ <arcgis-map basemap="streets-vector">
60
+ <!-- Position widgets using slots -->
61
+ <arcgis-zoom slot="top-left"></arcgis-zoom>
62
+ <arcgis-home slot="top-left"></arcgis-home>
63
+ <arcgis-compass slot="top-left"></arcgis-compass>
64
+
65
+ <arcgis-search slot="top-right"></arcgis-search>
66
+ <arcgis-layer-list slot="top-right"></arcgis-layer-list>
67
+
68
+ <arcgis-legend slot="bottom-left"></arcgis-legend>
69
+ <arcgis-scale-bar slot="bottom-right"></arcgis-scale-bar>
70
+
71
+ <!-- Popup must use popup slot -->
72
+ <arcgis-popup slot="popup"></arcgis-popup>
73
+ </arcgis-map>
74
+ ```
75
+
76
+ Available slots: `top-left`, `top-right`, `bottom-left`, `bottom-right`, `popup`, `manual`
77
+
78
+ ### Expand Component
79
+
80
+ Wrap widgets in `arcgis-expand` for collapsible behavior:
81
+
82
+ ```html
83
+ <arcgis-map basemap="streets-vector">
84
+ <arcgis-expand slot="top-right" expand-tooltip="Show Legend" mode="floating">
85
+ <arcgis-legend></arcgis-legend>
86
+ </arcgis-expand>
87
+
88
+ <arcgis-expand slot="top-left" expanded>
89
+ <arcgis-layer-list></arcgis-layer-list>
90
+ </arcgis-expand>
91
+ </arcgis-map>
92
+ ```
93
+
94
+ ### Reference Element (External Components)
95
+
96
+ Place components outside the map and reference them:
97
+
98
+ ```html
99
+ <calcite-shell>
100
+ <calcite-shell-panel slot="panel-start">
101
+ <arcgis-legend reference-element="arcgis-map"></arcgis-legend>
102
+ </calcite-shell-panel>
103
+
104
+ <arcgis-map id="arcgis-map" basemap="topo-vector">
105
+ <arcgis-zoom slot="top-left"></arcgis-zoom>
106
+ </arcgis-map>
107
+ </calcite-shell>
108
+ ```
109
+
110
+ ## Core Widget Approach
111
+
112
+ ### Adding Widgets to View
113
+
114
+ ```javascript
115
+ import Legend from "@arcgis/core/widgets/Legend.js";
116
+ import LayerList from "@arcgis/core/widgets/LayerList.js";
117
+ import Search from "@arcgis/core/widgets/Search.js";
118
+
119
+ // Create widget
120
+ const legend = new Legend({ view: view });
121
+
122
+ // Add to view UI
123
+ view.ui.add(legend, "bottom-left");
124
+
125
+ // Add multiple widgets
126
+ view.ui.add([
127
+ { component: legend, position: "bottom-left" },
128
+ { component: search, position: "top-right" }
129
+ ]);
130
+
131
+ // Add to specific index (order in position)
132
+ view.ui.add(legend, { position: "bottom-left", index: 0 });
133
+
134
+ // Remove widget
135
+ view.ui.remove(legend);
136
+ ```
137
+
138
+ ### Widget in Custom Container
139
+
140
+ ```html
141
+ <div id="legendDiv"></div>
142
+
143
+ <script type="module">
144
+ import Legend from "@arcgis/core/widgets/Legend.js";
145
+
146
+ const legend = new Legend({
147
+ view: view,
148
+ container: "legendDiv" // Or document.getElementById("legendDiv")
149
+ });
150
+ </script>
151
+ ```
152
+
153
+ ## Common Widgets
154
+
155
+ ### Legend
156
+
157
+ ```html
158
+ <!-- Map Component -->
159
+ <arcgis-legend slot="bottom-left"></arcgis-legend>
160
+ ```
161
+
162
+ ```javascript
163
+ // Core API
164
+ import Legend from "@arcgis/core/widgets/Legend.js";
165
+
166
+ const legend = new Legend({
167
+ view: view,
168
+ layerInfos: [{
169
+ layer: featureLayer,
170
+ title: "Custom Title"
171
+ }]
172
+ });
173
+
174
+ view.ui.add(legend, "bottom-left");
175
+ ```
176
+
177
+ ### LayerList
178
+
179
+ ```html
180
+ <!-- Map Component -->
181
+ <arcgis-layer-list slot="top-right"></arcgis-layer-list>
182
+ ```
183
+
184
+ ```javascript
185
+ // Core API with actions
186
+ import LayerList from "@arcgis/core/widgets/LayerList.js";
187
+
188
+ const layerList = new LayerList({
189
+ view: view,
190
+ listItemCreatedFunction: (event) => {
191
+ const item = event.item;
192
+ item.actionsSections = [[{
193
+ title: "Zoom to layer",
194
+ icon: "zoom-to-object",
195
+ id: "zoom-to"
196
+ }]];
197
+ }
198
+ });
199
+
200
+ layerList.on("trigger-action", (event) => {
201
+ if (event.action.id === "zoom-to") {
202
+ view.goTo(event.item.layer.fullExtent);
203
+ }
204
+ });
205
+
206
+ view.ui.add(layerList, "top-right");
207
+ ```
208
+
209
+ ### BasemapGallery
210
+
211
+ ```html
212
+ <!-- Map Component -->
213
+ <arcgis-basemap-gallery slot="top-right"></arcgis-basemap-gallery>
214
+ ```
215
+
216
+ ```javascript
217
+ // Core API
218
+ import BasemapGallery from "@arcgis/core/widgets/BasemapGallery.js";
219
+
220
+ const basemapGallery = new BasemapGallery({
221
+ view: view
222
+ });
223
+
224
+ view.ui.add(basemapGallery, "top-right");
225
+ ```
226
+
227
+ ### Search
228
+
229
+ ```html
230
+ <!-- Map Component -->
231
+ <arcgis-search slot="top-right"></arcgis-search>
232
+ ```
233
+
234
+ ```javascript
235
+ // Core API with custom sources
236
+ import Search from "@arcgis/core/widgets/Search.js";
237
+
238
+ const search = new Search({
239
+ view: view,
240
+ sources: [{
241
+ layer: featureLayer,
242
+ searchFields: ["name", "address"],
243
+ displayField: "name",
244
+ exactMatch: false,
245
+ outFields: ["*"],
246
+ name: "My Layer",
247
+ placeholder: "Search features"
248
+ }]
249
+ });
250
+
251
+ view.ui.add(search, "top-right");
252
+
253
+ // Events
254
+ search.on("select-result", (event) => {
255
+ console.log("Selected:", event.result);
256
+ });
257
+ ```
258
+
259
+ ### FeatureTable
260
+
261
+ ```html
262
+ <!-- Map Component -->
263
+ <arcgis-feature-table reference-element="arcgis-map"></arcgis-feature-table>
264
+ ```
265
+
266
+ ```javascript
267
+ // Core API
268
+ import FeatureTable from "@arcgis/core/widgets/FeatureTable.js";
269
+
270
+ const featureTable = new FeatureTable({
271
+ view: view,
272
+ layer: featureLayer,
273
+ container: "tableDiv",
274
+ visibleElements: {
275
+ header: true,
276
+ columnMenus: true,
277
+ selectionColumn: true
278
+ },
279
+ fieldConfigs: [
280
+ { name: "name", label: "Name" },
281
+ { name: "population", label: "Population" }
282
+ ]
283
+ });
284
+
285
+ // Selection events
286
+ featureTable.on("selection-change", (event) => {
287
+ console.log("Selected rows:", event.added);
288
+ });
289
+ ```
290
+
291
+ ### TimeSlider
292
+
293
+ ```html
294
+ <!-- Map Component -->
295
+ <arcgis-time-slider
296
+ slot="bottom-right"
297
+ layout="auto"
298
+ mode="time-window"
299
+ time-visible
300
+ loop>
301
+ </arcgis-time-slider>
302
+
303
+ <script type="module">
304
+ const timeSlider = document.querySelector("arcgis-time-slider");
305
+ await layer.load();
306
+
307
+ timeSlider.fullTimeExtent = layer.timeInfo.fullTimeExtent;
308
+ timeSlider.stops = {
309
+ interval: layer.timeInfo.interval
310
+ };
311
+ </script>
312
+ ```
313
+
314
+ ```javascript
315
+ // Core API
316
+ import TimeSlider from "@arcgis/core/widgets/TimeSlider.js";
317
+
318
+ const timeSlider = new TimeSlider({
319
+ view: view,
320
+ mode: "time-window", // instant, time-window, cumulative-from-start, cumulative-from-end
321
+ fullTimeExtent: layer.timeInfo.fullTimeExtent,
322
+ stops: {
323
+ interval: {
324
+ value: 1,
325
+ unit: "hours"
326
+ }
327
+ },
328
+ playRate: 1000, // ms between stops
329
+ loop: true
330
+ });
331
+
332
+ view.ui.add(timeSlider, "bottom-right");
333
+
334
+ // Events
335
+ timeSlider.watch("timeExtent", (timeExtent) => {
336
+ console.log("Time changed:", timeExtent.start, timeExtent.end);
337
+ });
338
+ ```
339
+
340
+ ### Print
341
+
342
+ ```html
343
+ <!-- Map Component -->
344
+ <arcgis-print slot="top-right"></arcgis-print>
345
+ ```
346
+
347
+ ```javascript
348
+ // Core API
349
+ import Print from "@arcgis/core/widgets/Print.js";
350
+
351
+ const print = new Print({
352
+ view: view,
353
+ printServiceUrl: "https://utility.arcgisonline.com/arcgis/rest/services/Utilities/PrintingTools/GPServer/Export%20Web%20Map%20Task"
354
+ });
355
+
356
+ view.ui.add(print, "top-right");
357
+ ```
358
+
359
+ ## Calcite Design System Integration
360
+
361
+ ### Basic Layout with Calcite
362
+
363
+ ```html
364
+ <!DOCTYPE html>
365
+ <html>
366
+ <head>
367
+ <script type="module" src="https://js.arcgis.com/calcite-components/3.3.3/calcite.esm.js"></script>
368
+ <script src="https://js.arcgis.com/4.34/"></script>
369
+ <script type="module" src="https://js.arcgis.com/4.34/map-components/"></script>
370
+ <style>
371
+ html, body { height: 100%; margin: 0; }
372
+ </style>
373
+ </head>
374
+ <body class="calcite-mode-light">
375
+ <calcite-shell>
376
+ <!-- Header -->
377
+ <calcite-navigation slot="header">
378
+ <calcite-navigation-logo slot="logo" heading="My Map App"></calcite-navigation-logo>
379
+ </calcite-navigation>
380
+
381
+ <!-- Side Panel -->
382
+ <calcite-shell-panel slot="panel-start">
383
+ <calcite-panel heading="Layers">
384
+ <arcgis-layer-list reference-element="map"></arcgis-layer-list>
385
+ </calcite-panel>
386
+ </calcite-shell-panel>
387
+
388
+ <!-- Map -->
389
+ <arcgis-map id="map" basemap="streets-vector">
390
+ <arcgis-zoom slot="top-left"></arcgis-zoom>
391
+ </arcgis-map>
392
+
393
+ <!-- End Panel -->
394
+ <calcite-shell-panel slot="panel-end">
395
+ <calcite-panel heading="Legend">
396
+ <arcgis-legend reference-element="map"></arcgis-legend>
397
+ </calcite-panel>
398
+ </calcite-shell-panel>
399
+ </calcite-shell>
400
+ </body>
401
+ </html>
402
+ ```
403
+
404
+ ### Calcite Action Bar
405
+
406
+ ```html
407
+ <calcite-shell>
408
+ <calcite-shell-panel slot="panel-start">
409
+ <calcite-action-bar slot="action-bar">
410
+ <calcite-action icon="layers" text="Layers" data-panel="layers"></calcite-action>
411
+ <calcite-action icon="legend" text="Legend" data-panel="legend"></calcite-action>
412
+ <calcite-action icon="bookmark" text="Bookmarks" data-panel="bookmarks"></calcite-action>
413
+ </calcite-action-bar>
414
+
415
+ <calcite-panel id="layers" heading="Layers">
416
+ <arcgis-layer-list reference-element="map"></arcgis-layer-list>
417
+ </calcite-panel>
418
+
419
+ <calcite-panel id="legend" heading="Legend" hidden>
420
+ <arcgis-legend reference-element="map"></arcgis-legend>
421
+ </calcite-panel>
422
+ </calcite-shell-panel>
423
+
424
+ <arcgis-map id="map" basemap="topo-vector"></arcgis-map>
425
+ </calcite-shell>
426
+
427
+ <script>
428
+ // Toggle panels on action click
429
+ document.querySelectorAll("calcite-action").forEach(action => {
430
+ action.addEventListener("click", () => {
431
+ const panelId = action.dataset.panel;
432
+ document.querySelectorAll("calcite-panel").forEach(panel => {
433
+ panel.hidden = panel.id !== panelId;
434
+ });
435
+ });
436
+ });
437
+ </script>
438
+ ```
439
+
440
+ ### Common Calcite Components
441
+
442
+ | Component | Purpose |
443
+ |-----------|---------|
444
+ | `calcite-shell` | App layout container |
445
+ | `calcite-shell-panel` | Side panels |
446
+ | `calcite-panel` | Content panel |
447
+ | `calcite-navigation` | Header/footer |
448
+ | `calcite-action-bar` | Icon button bar |
449
+ | `calcite-action` | Icon button |
450
+ | `calcite-button` | Standard button |
451
+ | `calcite-input` | Text input |
452
+ | `calcite-list` | List container |
453
+ | `calcite-list-item` | List item |
454
+ | `calcite-card` | Card container |
455
+ | `calcite-modal` | Modal dialog |
456
+ | `calcite-alert` | Alert message |
457
+ | `calcite-loader` | Loading indicator |
458
+
459
+ ### Theming
460
+
461
+ ```html
462
+ <!-- Light mode -->
463
+ <body class="calcite-mode-light">
464
+
465
+ <!-- Dark mode -->
466
+ <body class="calcite-mode-dark">
467
+
468
+ <!-- Custom theme colors -->
469
+ <style>
470
+ :root {
471
+ --calcite-color-brand: #007ac2;
472
+ --calcite-color-brand-hover: #005a8e;
473
+ --calcite-color-text-1: #323232;
474
+ }
475
+ </style>
476
+ ```
477
+
478
+ ## Custom Widget Placement
479
+
480
+ ### Manual Positioning
481
+
482
+ ```javascript
483
+ // Add widget at specific position
484
+ view.ui.add(widget, {
485
+ position: "manual",
486
+ index: 0
487
+ });
488
+
489
+ // Position with CSS
490
+ document.getElementById("myWidget").style.cssText = `
491
+ position: absolute;
492
+ top: 10px;
493
+ left: 50%;
494
+ transform: translateX(-50%);
495
+ `;
496
+ ```
497
+
498
+ ### DOM Container
499
+
500
+ ```html
501
+ <div id="mapDiv" style="position: relative;">
502
+ <div id="customWidget" style="position: absolute; top: 10px; right: 10px; z-index: 1;">
503
+ <!-- Custom content -->
504
+ </div>
505
+ </div>
506
+ ```
507
+
508
+ ## Widget Events
509
+
510
+ ```javascript
511
+ // Search select
512
+ search.on("select-result", (event) => {
513
+ console.log(event.result);
514
+ });
515
+
516
+ // LayerList trigger action
517
+ layerList.on("trigger-action", (event) => {
518
+ console.log(event.action, event.item);
519
+ });
520
+
521
+ // TimeSlider time change
522
+ timeSlider.watch("timeExtent", (value) => {
523
+ console.log(value.start, value.end);
524
+ });
525
+
526
+ // FeatureTable selection
527
+ featureTable.on("selection-change", (event) => {
528
+ console.log(event.added, event.removed);
529
+ });
530
+ ```
531
+
532
+ ## TypeScript Usage
533
+
534
+ Widget configurations use autocasting with `type` properties. For TypeScript safety, use `as const`:
535
+
536
+ ```typescript
537
+ // Use 'as const' for widget configurations
538
+ const layerList = new LayerList({
539
+ view: view,
540
+ listItemCreatedFunction: (event) => {
541
+ const item = event.item;
542
+ item.actionsSections = [[{
543
+ title: "Zoom to layer",
544
+ icon: "zoom-to-object",
545
+ id: "zoom-to"
546
+ }]];
547
+ }
548
+ });
549
+
550
+ // For layer configurations in widgets
551
+ const featureTable = new FeatureTable({
552
+ view: view,
553
+ layer: featureLayer,
554
+ fieldConfigs: [
555
+ { name: "name", label: "Name" },
556
+ { name: "population", label: "Population" }
557
+ ]
558
+ });
559
+ ```
560
+
561
+ > **Tip:** See [arcgis-core-maps skill](../arcgis-core-maps/SKILL.md) for detailed guidance on autocasting vs explicit classes.
562
+
563
+ ## Common Pitfalls
564
+
565
+ 1. **Missing reference-element**: When placing components outside the map, use `reference-element` attribute
566
+
567
+ 2. **Slot names are specific**: Use exact slot names (`top-left`, not `topleft`)
568
+
569
+ 3. **Calcite CSS not loading**: Ensure Calcite script is loaded before using Calcite components
570
+
571
+ 4. **Widget container conflicts**: Don't add the same widget to both a container and view.ui
572
+
573
+ 5. **Dark/light mode mismatch**: Add `calcite-mode-light` or `calcite-mode-dark` class to body
574
+