Treemap
Area-encoded topography: which parts of a structure carry the weight, proportionally. Answers 'which area is worst' where ClusterMap answers 'who is affected and why'.
rendered, live
the wire — click a line to scrub
the contract — Treemap in catalog.json
{
"type": "object",
"description": "Area-encoded topography: which parts of a structure carry the weight, proportionally. Answers 'which area is worst' where ClusterMap answers 'who is affected and why'.",
"properties": {
"component": {
"const": "Treemap"
},
"label": {
"$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/DynamicString",
"description": "Title and accessible name, e.g. 'Support volume by product area'. Required."
},
"valueLabel": {
"type": "string",
"description": "What the area means, e.g. 'cases' or 'ARR at risk'. Required — an area encoding with no stated unit cannot be read."
},
"subjectKind": {
"type": "string",
"description": "What one rectangle is, in your domain's words, e.g. 'product_area'. Default 'area'; merged into itemAction context with the item's id."
},
"windowStart": {
"type": "string",
"description": "ISO 8601 start of the observation window. The renderer formats it in the host locale — keep the period out of the label prose."
},
"windowEnd": {
"type": "string",
"description": "ISO 8601 end of the observation window."
},
"items": {
"oneOf": [
{
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"label": {
"type": "string",
"description": "Short name of the area, e.g. 'Reporting'."
},
"value": {
"type": "number",
"description": "What the area encodes. Raw number in the units of valueLabel. When children are present this should be their total; if it disagrees, the children win and this is ignored."
},
"intent": {
"enum": [
"good",
"bad",
"warning",
"info",
"neutral"
]
},
"trend": {
"enum": [
"up",
"down",
"flat"
],
"description": "Direction of the underlying signal — describes, never judges. Independent of intent: volume rising is 'up' and usually 'bad'; the same rise in revenue is 'up' and 'good'. Without it, a worsening area and a merely large one look identical."
},
"children": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"label": {
"type": "string",
"description": "Short name, e.g. 'Export totals'."
},
"value": {
"type": "number",
"description": "What the area encodes. Raw number in the units of valueLabel — never a formatted string."
},
"intent": {
"enum": [
"good",
"bad",
"warning",
"info",
"neutral"
]
},
"trend": {
"enum": [
"up",
"down",
"flat"
],
"description": "Direction of the underlying signal — describes, never judges. Independent of intent: volume rising is 'up' and usually 'bad'; the same rise in revenue is 'up' and 'good'. Without it, a worsening area and a merely large one look identical."
}
},
"required": [
"id",
"label",
"value"
],
"additionalProperties": false
},
"description": "One level of nesting, and only one — an area's parts. Deeper trees are not expressible: past two levels the rectangles are too small to label honestly."
}
},
"required": [
"id",
"label",
"value"
],
"additionalProperties": false
}
},
{
"$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/DataBinding"
}
],
"description": "The areas, sized by value. Order does not matter — the layout sorts by value. Bind with {\"path\": ...} to stream."
},
"itemAction": {
"$ref": "https://a2ui.org/specification/v1_0/common_types.json#/$defs/Action",
"description": "Fired on rectangle activation. subjectKind, subjectId (the item's id), itemLabel, and — for a child — parentId are merged into its context automatically."
}
},
"required": [
"label",
"valueLabel",
"items"
]
}the prompt-pack — paste into your agent
### Treemap — which parts carry the weight
Area-encoded topography. Answers _which part of the product hurts, proportionally_ — where
ClusterMap answers _who is affected, and why_. Reach for it when the question is about structure
rather than entities, or when there are too many groups for cards to stay readable.
| prop | type | notes |
| ------------- | ------------------------------ | ----------------------------------------------------------- |
| `label` | string, required | title and accessible name |
| `valueLabel` | string, required | what the area means — `"cases"`, `"ARR at risk"` |
| `items` | item[] \| `{"path"}`, required | shape below |
| `subjectKind` | string | what one rectangle is; default `"area"` |
| `windowStart` | ISO 8601 string | observation window — keep the period out of the label prose |
| `windowEnd` | ISO 8601 string | ditto; the renderer formats both in the host locale |
| `itemAction` | action | subject + `itemLabel` (+ `parentId` for a child) merged in |
Item shape — `id`, `label`, `value` required. `value` is a raw number in the units of
`valueLabel`, never a formatted string. `children` gives **one** level of nesting and only one; a
parent's `value` should equal its children's total.
`intent` and `trend` are independent axes, and an area that is _getting worse_ needs both — put
the direction in `trend`, not in the title text. `intent` says how bad it is now; `trend` says
which way it is moving (`up` / `down` / `flat`, describing the value, never judging it). Omit
either one when you weren't told: an unstated intent is not `"neutral"`, and an unstated direction
is not `"flat"` — inventing one puts a claim on screen that nobody made.
```
{"id":"reporting","label":"Reporting","value":312,"intent":"bad","trend":"up","children":[{"id":"export-totals","label":"Export totals","value":190,"intent":"bad","trend":"up"},{"id":"scheduling","label":"Scheduled sends","value":122,"trend":"flat"}]}
```
```
{"id":"friction","component":"Treemap","label":"Support volume by product area","valueLabel":"cases","subjectKind":"product_area","windowStart":"2026-08-01T00:00:00Z","items":{"path":"/areas"},"itemAction":{"event":{"name":"area_drilled","context":{"view":"cases"}}}}
```
Drilling fires the event and nothing else — what happens next is your next turn. Push a
`DrillStack` level by writing its `activeIndex`, or send the components for the deeper view.