---
name: arcgis-arcade
description: Write Arcade expressions for dynamic calculations in popups, renderers, labels, and field calculations. Use for data-driven styling, custom labels, and computed fields.
---
# ArcGIS Arcade Expressions
Use this skill for writing Arcade expressions for popups, renderers, labels, and calculations.
## Import Patterns
### Direct ESM Imports
```javascript
import * as arcade from "@arcgis/core/arcade.js";
```
### Dynamic Imports (CDN)
```javascript
const arcade = await $arcgis.import("@arcgis/core/arcade.js");
```
## Arcade Basics
Arcade is an expression language for ArcGIS. It's used for:
- Dynamic popup content
- Data-driven rendering
- Custom labels
- Field calculations
- Form validation
### Basic Syntax
```arcade
// Variables
var population = $feature.population;
var area = $feature.area_sqkm;
// Calculations
var density = population / area;
// Return result
return Round(density, 2);
```
## Arcade in PopupTemplates
### Expression Infos
```javascript
const popupTemplate = {
title: "{name}",
expressionInfos: [
{
name: "population-density",
title: "Population Density",
expression: "Round($feature.population / $feature.area_sqkm, 2)",
},
{
name: "formatted-date",
title: "Formatted Date",
expression: "Text($feature.created_date, 'MMMM D, YYYY')",
},
],
content: "Density: {expression/population-density} people/km²",
};
```
### Complex Expressions
```javascript
const popupTemplate = {
title: "{name}",
expressionInfos: [
{
name: "predominant-category",
title: "Predominant Category",
expression: `
var fields = [
{ value: $feature.category_a, alias: "Category A" },
{ value: $feature.category_b, alias: "Category B" },
{ value: $feature.category_c, alias: "Category C" }
];
var maxValue = -Infinity;
var maxCategory = "";
for (var i in fields) {
if (fields[i].value > maxValue) {
maxValue = fields[i].value;
maxCategory = fields[i].alias;
}
}
return maxCategory;
`,
},
],
content: [
{
type: "text",
text: "The predominant category is: {expression/predominant-category}",
},
{
type: "fields",
fieldInfos: [
{
fieldName: "expression/predominant-category",
},
],
},
],
};
```
## Arcade in Renderers
### Value Expression
```javascript
const renderer = {
type: "unique-value",
valueExpression: `
var labor = $feature.labor_force;
var notLabor = $feature.not_in_labor_force;
if (labor > notLabor) {
return "In labor force";
} else {
return "Not in labor force";
}
`,
valueExpressionTitle: "Labor Force Status",
uniqueValueInfos: [
{
value: "In labor force",
symbol: { type: "simple-fill", color: "blue" },
},
{
value: "Not in labor force",
symbol: { type: "simple-fill", color: "orange" },
},
],
};
```
### Visual Variable Expression
```javascript
const renderer = {
type: "simple",
symbol: { type: "simple-marker", color: "red" },
visualVariables: [
{
type: "size",
valueExpression: "Sqrt($feature.population) * 0.1",
valueExpressionTitle: "Population (scaled)",
stops: [
{ value: 10, size: 4 },
{ value: 100, size: 40 },
],
},
{
type: "opacity",
valueExpression: "($feature.value / $feature.max_value) * 100",
valueExpressionTitle: "Percentage of max",
stops: [
{ value: 20, opacity: 0.2 },
{ value: 80, opacity: 1 },
],
},
],
};
```
## Arcade in Labels
```javascript
layer.labelingInfo = [
{
symbol: {
type: "text",
color: "black",
font: { size: 10 },
},
labelExpressionInfo: {
expression: `
var name = $feature.name;
var pop = $feature.population;
if (pop > 1000000) {
return name + " (" + Round(pop/1000000, 1) + "M)";
} else if (pop > 1000) {
return name + " (" + Round(pop/1000, 0) + "K)";
}
return name;
`,
},
where: "population > 50000",
},
];
```
## Common Arcade Functions
### Math Functions
```arcade
Round(3.14159, 2) // 3.14
Floor(3.9) // 3
Ceil(3.1) // 4
Abs(-5) // 5
Sqrt(16) // 4
Pow(2, 3) // 8
Min(1, 2, 3) // 1
Max(1, 2, 3) // 3
Sum([1, 2, 3]) // 6
Mean([1, 2, 3]) // 2
```
### Text Functions
```arcade
Upper("hello") // "HELLO"
Lower("HELLO") // "hello"
Trim(" hello ") // "hello"
Left("hello", 2) // "he"
Right("hello", 2) // "lo"
Mid("hello", 2, 2) // "ll"
Find("l", "hello") // 2
Replace("hello", "l", "L") // "heLLo"
Split("a,b,c", ",") // ["a", "b", "c"]
Concatenate(["a", "b"]) // "ab"
```
### Date Functions
```arcade
Now() // Current date/time
Today() // Current date
Year($feature.date_field) // Extract year
Month($feature.date_field) // Extract month (1-12)
Day($feature.date_field) // Extract day
DateDiff(Now(), $feature.date, "days") // Days between dates
Text($feature.date, "MMMM D, YYYY") // Format date
```
### Geometry Functions
```arcade
Area($feature, "square-kilometers")
Length($feature, "kilometers")
Centroid($feature)
Buffer($feature, 100, "meters")
Intersects($feature, $otherFeature)
Contains($feature, $point)
```
### Conditional Functions
```arcade
// IIf (inline if)
IIf($feature.value > 100, "High", "Low")
// When (multiple conditions)
When(
$feature.type == "A", "Type A",
$feature.type == "B", "Type B",
"Other"
)
// Decode (value matching)
Decode($feature.code,
1, "One",
2, "Two",
3, "Three",
"Unknown"
)
```
### Array Functions
```arcade
var arr = [1, 2, 3, 4, 5];
Count(arr) // 5
First(arr) // 1
Last(arr) // 5
IndexOf(arr, 3) // 2
Includes(arr, 3) // true
Push(arr, 6) // [1, 2, 3, 4, 5, 6]
Reverse(arr) // [5, 4, 3, 2, 1]
Sort(arr) // [1, 2, 3, 4, 5]
Slice(arr, 1, 3) // [2, 3]
```
## Feature Access
```arcade
// Current feature
$feature.fieldName
// All features in layer (for aggregation)
var allFeatures = FeatureSet($layer);
var filtered = Filter(allFeatures, "type = 'A'");
var total = Sum(filtered, "value");
// Related records
var related = FeatureSetByRelationshipName($feature, "relationshipName");
// Global variables
$map // Reference to map
$view // Reference to view
$datastore // Reference to data store
```
## Execute Arcade Programmatically
```javascript
import * as arcade from "@arcgis/core/arcade.js";
// Create profile
const profile = {
variables: [
{
name: "$feature",
type: "feature",
},
],
};
// Compile expression
const executor = await arcade.createArcadeExecutor(
"Round($feature.value * 100, 2)",
profile,
);
// Execute with feature
const result = await executor.executeAsync({
$feature: graphic,
});
console.log("Result:", result);
```
> **Note:** In v5.0, `ExecuteContext.lruCache` is deprecated. Use `ExecuteContext.cache` instead.
## Arcade in HTML (Script Tags)
```html
```
## Arcade Expression Profiles
Different Arcade profiles expose different global variables and functions:
| Profile | Global Variables | Used For |
| ------------------ | ------------------------------------------ | --------------------------- |
| `popup` | `$feature`, `$layer`, `$map`, `$datastore` | Popup content |
| `visualization` | `$feature`, `$view` | Renderers, visual variables |
| `labeling` | `$feature`, `$view` | Label expressions |
| `field-calculate` | `$feature`, `$layer` | Field calculations |
| `form-calculation` | `$feature`, `$layer`, `$originalFeature` | Form calculated expressions |
| `constraint` | `$feature`, `$layer`, `$originalFeature` | Form validation |
| `alias` | `$feature`, `$layer` | Cluster popup aliases |
## Reference Samples
- `popuptemplate-arcade` - Arcade expressions in PopupTemplates
- `popuptemplate-arcade-expression-content` - Arcade expression content in popups
- `visualization-arcade` - Arcade-driven visualization
- `arcade-execute-chart` - Execute Arcade with charting
## Common Pitfalls
1. **Null values**: Always check for nulls with `IsEmpty($feature.field)` before arithmetic operations. Dividing by null or adding to null produces null.
```arcade
// Anti-pattern: no null check
return $feature.population / $feature.area;
```
```arcade
// Correct: check for null
if (IsEmpty($feature.area) || $feature.area == 0) {
return "N/A";
}
return Round($feature.population / $feature.area, 2);
```
2. **Type coercion**: Use `Number()` or `Text()` for explicit conversion when mixing types.
3. **Case sensitivity**: Arcade function names are case-insensitive, but field names must match the source data exactly.
4. **Performance**: Complex expressions in renderers and labels evaluate per feature per frame. Keep them simple for large datasets.
5. **Debugging**: Use the `Console()` function to debug expressions. Output appears in the browser's developer console.
6. **FeatureSet queries**: `FeatureSet()` and `Filter()` execute server-side queries. They can be slow in popup expressions if the layer has many features.
## Related Skills
- See `arcgis-popup-templates` for popup template configuration
- See `arcgis-visualization` for renderer and symbol configuration
- See `arcgis-smart-mapping` for data-driven visualization
- See `arcgis-coding-components` for the `` component