Write Arcade expressions for dynamic calculations in popups, renderers, labels, and field calculations. Use for data-driven styling, custom labels, and computed fields.
80
75%
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Passed
No known issues
Optimize this skill with Tessl
npx tessl skill review --optimize ./contexts/4.34/skills/arcgis-arcade/SKILL.mdUse this skill for writing Arcade expressions for popups, renderers, labels, and calculations.
Arcade is an expression language for ArcGIS. It's used for:
// Variables
var population = $feature.population;
var area = $feature.area_sqkm;
// Calculations
var density = population / area;
// Return result
return Round(density, 2);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²"
};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"
}]
}
]
};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" }
}
]
};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 }
]
}]
};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"
}];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]) // 2Upper("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"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 dateArea($feature, "square-kilometers")
Length($feature, "kilometers")
Centroid($feature)
Buffer($feature, 100, "meters")
Intersects($feature, $otherFeature)
Contains($feature, $point)// 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"
)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]// 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 storeimport * 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);<script type="text/plain" id="my-expression">
var total = $feature.value_a + $feature.value_b;
var percentage = Round((total / $feature.max_value) * 100, 1);
return percentage + "%";
</script>
<script type="module">
const expression = document.getElementById("my-expression").text;
const popupTemplate = {
expressionInfos: [{
name: "my-calc",
expression: expression
}],
content: "Value: {expression/my-calc}"
};
</script>Arcade expression configurations use autocasting. For TypeScript safety, use as const:
// Use 'as const' for expression-based visualizations
layer.renderer = {
type: "simple",
symbol: { type: "simple-marker" },
visualVariables: [{
type: "size",
valueExpression: "$feature.population / $feature.area",
stops: [
{ value: 50, size: 4 },
{ value: 500, size: 20 }
]
}]
} as const;Tip: See arcgis-core-maps skill for detailed guidance on autocasting vs explicit classes.
popuptemplate-arcade - Arcade expressions in PopupTemplatespopuptemplate-arcade-expression-content - Arcade expression content in popupsNull values: Check for nulls with IsEmpty($feature.field)
Type coercion: Use Number() or Text() for explicit conversion
Case sensitivity: Arcade is case-insensitive for functions but field names match exactly
Performance: Complex expressions in renderers can slow performance
Debugging: Use Console() function to debug expressions
d84407b
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.