Skip to main content

Fragment Computed Values

Fragment computed values let AppConfig derive primitive values before fragment view fields and constraints are applied. Use them when a fragment needs small declarative decisions such as responsive line counts, focused colors, clamped artwork sizes, or constraint margins based on cell size.

Computed values live in a fragment's _dataMap.computed array and are referenced from view fields as exact computed.name strings.

Host-triggered fragment inputs are evaluated in declaration order and feed exact view fields or numeric constraint argumentsHost-triggered fragment inputs are evaluated in declaration order and feed exact view fields or numeric constraint arguments

Computed values derive primitive fields from runtime inputs, then feed exact computed.name view fields, status styles, and numeric constraint arguments.

{
"cells": {
"adaptiveCard": {
"$supportsDataMap": true,
"width": 640,
"height": 260,
"views": {
"base": [
{
"id": "titleLabel",
"subType": "Label",
"text": "${data.title}",
"width": 360,
"height": 72,
"wrap": "computed.titleWrap",
"maxLines": "computed.titleLines"
}
],
"normal": {},
"focused": {
"titleLabel": {
"color": "computed.titleColor"
}
}
},
"_dataMap": {
"view": {},
"data": {},
"fn": {},
"computed": [
{ "name": "isWide", "fn": "compare", "args": ["cell.width", "gt", 400] },
{ "name": "titleLines", "fn": "select", "args": ["computed.isWide", 2, 1] },
{ "name": "titleWrap", "fn": "select", "args": ["computed.isWide", true, false] },
{ "name": "titleColor", "fn": "select", "args": ["focus", "#ff3b30", "#ffffff"] }
]
}
}
}
}

The feature is intentionally small: it evaluates numbers, strings, and booleans. It does not replace fragment callbacks for measurement, host-side behavior, async data, or multi-view side effects.

Evaluation Model

Computed variables are evaluated in declaration order each time the fragment runtime calls applyFragmentComputed.

The current runtime recomputes values at these host-controlled points:

  • DynamicCell fragments when an item is bound, its effective cell dimensions change during binding, or the view status changes.
  • CollectionView header fragments when a data-mapped header is configured with row data.
  • FragmentView when its width or height changes, when its view status is applied, and when an itemContent update also runs a constraint pass.

FragmentView currently does not recompute a computed-only view map for a data-only itemContent change when the fragment has no constraints. If a standalone fragment derives fields from data.*, ensure it also runs a constraint pass or trigger another supported recomputation point, such as a relevant size or status update. DynamicCell does not have this data-only limitation.

After evaluation, the resolved values are stored on the fragment as computedValues. The fragment provider then substitutes exact computed.name strings in fragment view maps and status styles.

Computed values also flow into fragment constraints. Constraint arguments that expect numbers can use computed.name, which is useful for margins, insets, and aspect ratios.

These references are sampled when a host runs the computed pass. The computed system does not subscribe directly to deviceLayout or the keyboard-insets service, so a device, safe-area, or keyboard change does not by itself promise a fragment recomputation.

Declaration Shape

Each computed variable has this shape:

{
name: string;
fn: 'compare' | 'select' | 'clamp' | 'min' | 'max' | 'multiply' | 'add' | 'subtract' | 'divide';
args: Array<number | string | boolean>;
}

Names must be unique inside the fragment. A computed value can reference a value declared earlier in the same array with computed.otherName, but it cannot reference a later value.

References

Computed arguments support these references:

ReferenceResult
computed.nameA previously declared computed value.
data.path.to.valueA primitive value from the current item or FragmentView data object.
cell.widthThe current fragment host width, or 0 when unavailable.
cell.heightThe current fragment host height, or 0 when unavailable.
focus1 when the status is Focused or FocusSelected; otherwise 0.
screen.widthdeviceLayout.designWidth, falling back to the device resolution width and then 0.
screen.heightdeviceLayout.designHeight, falling back to the device resolution height and then 0.
safeArea.insets.topDrawing-safe top inset from deviceLayout, falling back to screenInfo.safeAreaInsets.top and then 0.
safeArea.insets.rightDrawing-safe right inset from deviceLayout, falling back to screenInfo.safeAreaInsets.right and then 0.
safeArea.insets.bottomDrawing-safe bottom inset from deviceLayout, falling back to screenInfo.safeAreaInsets.bottom and then 0.
safeArea.insets.leftDrawing-safe left inset from deviceLayout, falling back to screenInfo.safeAreaInsets.left and then 0.
keyboard.heightCurrent keyboard height from keyboardInsetsService, or 0 when the service is unavailable.
keyboard.insets.bottomCurrent keyboard bottom inset, or 0 when unavailable.
keyboard.visible1 while the keyboard is visible; otherwise 0.

data.* references must resolve to a number, string, or boolean. Missing data, object values, and array values fail evaluation.

screen.* and safeArea.insets.* read the shared deviceLayout IoC object, not a one-off device snapshot. Keyboard references read the current keyboardInsetsService state. The computed-value resolver does not define a safeArea.interactionInsets.* namespace. A later host-triggered computed pass sees the latest values in these services; the services do not push updates directly into fragments.

View geometry references such as poster.right or titleLabel.width are not allowed in computed arguments. Use fragment constraints for child-to-child geometry.

Functions

FunctionArgsResult
compare[left, operator, right]Boolean comparison. Operators: eq, ===, ne, !==, gt, >, gte, >=, lt, <, lte, <=. Equality can compare any primitive; ordered comparisons require numbers.
select[condition, whenTrue, whenFalse]Returns one of two values. The condition must be a boolean or number.
clamp[value, min, max]Number constrained between min and max.
min[value, ...values]Smallest number. Requires at least one argument.
max[value, ...values]Largest number. Requires at least one argument.
multiply[left, right, ...values]Product of all numeric arguments.
add[left, right, ...values]Sum of all numeric arguments.
subtract[left, right]Numeric subtraction.
divide[left, right]Numeric division. Division by zero fails evaluation.

Numeric functions require finite numbers after references have been resolved.

Binding View Fields

A field in views.base can use a computed value when the entire field value is an exact computed.name string.

{
"id": "poster",
"subType": "Poster",
"width": "computed.posterWidth",
"visible": "computed.posterVisible"
}

For views.base, computed values are not interpolated inside longer strings, objects, or arrays. Use computed.posterWidth, not "${computed.posterWidth}", "width: computed.posterWidth", or [0, "computed.y"].

When AppConfig resolves a fragment with $supportsDataMap, exact computed references are moved into the fragment data map's view section. At runtime only those fields are updated by computed substitution.

Status styles use a different application path. The provider recursively walks the selected status update object, so an exact computed.name reference can also appear inside a status array or nested object. It still must be the whole leaf value; substring interpolation is not supported.

{
"views": {
"focused": {
"titleLabel": {
"color": "computed.titleColor",
"translation": ["computed.focusedX", 24]
}
}
}
}

Using Computed Values In Constraints

Fragment constraints can use computed values only in numeric argument positions. This works for margins, insets, and aspect ratios. The inline {{constraint.*(...)}} parser accepts literal numeric arguments, so a computed.name numeric argument must be written in an explicit _dataMap.constraints rule:

{
"_dataMap": {
"view": {},
"data": {},
"fn": {},
"computed": [
{ "name": "margin", "fn": "select", "args": ["focus", 24, 12] },
{ "name": "isWide", "fn": "compare", "args": ["cell.width", "gt", 500] },
{ "name": "ratio", "fn": "select", "args": ["computed.isWide", 1.7777777778, 1.3333333333] }
],
"constraints": [
{ "viewId": "titleLabel", "property": "x", "fn": "pin", "args": ["poster", "left", "right", "computed.margin"] },
{ "viewId": "poster", "property": "height", "fn": "aspectRatio", "args": ["computed.ratio"] }
]
}
}

String-only constraint arguments cannot be computed. For example, pin requires the referenced view and edge arguments to stay literal strings.

Common Patterns

Use computed values for cell-size responsive fields:

{
"computed": [
{ "name": "rawPosterWidth", "fn": "multiply", "args": ["cell.width", 0.34] },
{ "name": "posterWidth", "fn": "clamp", "args": ["computed.rawPosterWidth", 120, 280] }
]
}

Use them for focus-aware presentation:

{
"computed": [
{ "name": "titleColor", "fn": "select", "args": ["focus", "#ff3b30", "#ffffff"] },
{ "name": "posterVisible", "fn": "select", "args": ["focus", true, false] }
]
}

Use them for item-data decisions:

{
"computed": [
{ "name": "badgeRawWidth", "fn": "multiply", "args": ["data.priority", 24] },
{ "name": "badgeWidth", "fn": "clamp", "args": ["computed.badgeRawWidth", 56, 128] }
]
}

Failure Cases

Computed evaluation fails when:

  • a variable is missing name
  • two variables use the same name
  • a variable references computed.name before that value has been declared
  • a data.* reference does not resolve to a primitive value
  • a numeric function receives a non-number or non-finite number
  • divide receives 0 as its divisor
  • a device, safe-area, or keyboard reference uses an unknown name
  • a computed argument uses view geometry such as poster.right
  • a constraint uses computed.name in a string-only argument position

Keep computed variables close to the fields they serve and keep names specific. If a value needs child measurement, asynchronous state, or coordinated updates across several nodes, use fragment callbacks instead.

Talk to us