AccountedPro - Layout JSON reference
For developers, and for anyone copying a view between sites. The JSON panel in the builder is read/write, so a layout can be pasted in whole.
A layout is one document — an Advanced List Layout whose layout_json holds the entire structure. It is validated on save against a schema, so a malformed layout is refused at the door rather than breaking a list at render time.
The shape
{
"doctype_name": "Sales Order",
"title": "Dispatch Board",
"page_length": 20,
"row_click": "expand", // "open" | "expand" | "none"
"auto_refresh_seconds": 300,
"data_source": { "type": "standard" },
"filter_tree": { … }, // the layout's own base condition
"group_by": "status",
"columns": [ … ],
"tabs": [ … ],
"cards": [ … ],
"filters": [ … ],
"header_buttons": [ … ],
"expanded_row": { "blocks": [ … ] },
"row_style": [ … ],
"theme": { … }
}
Accepted values
| Key | Values |
|---|---|
row_click |
expand, open, none |
data_source.type |
standard, server_script |
Element type |
field, virtual, static, button, chips, group, comments, image, related |
Block type |
section, child_table, comments, related |
Related display |
count, chips, sum, label |
Action type |
server_script, whitelisted, set_value, url, route, new_doc |
Card value.type |
count, sum, avg, payload_key |
Filter type |
select, link, period, number_operator, text, date_range, check |
mobile |
show, hide, only |
| Alignment | left, center, right |
Format kind |
currency, percent, float, int, date, datetime, relative, duration, text |
| Density | compact, cosy, comfortable |
| View mode | Table, Cards, Board |
theme.group_header.order |
value, value_desc, count, list |
| Link hover | underline, color, underline_color, highlight, none, "" |
Conditions
Three shapes are accepted, and they mix:
{ "all": [ … ] } // AND
{ "any": [ … ] } // OR
{ "op": "and", "not": false, "children": [ … ] } // what the builder writes
A leaf:
{
"field": "currency",
"op": "=",
"value": "CAD",
"not": false,
"hops": [ { "field": "price_list", "doctype": "Price List" } ]
}
hops is the drill-down: each entry names a Link field and the DocType it lands on, and field is the field at the end of the chain. Ten levels maximum.
Operators: =, !=, >, >=, <, <=, in, not in, contains, not contains, is set, is not set, between, timespan.
Values may be literals, @me, or a relative date (today, -7d, start of month…).
A tab
{
"id": "tab_mine",
"label": "My Forms",
"count": true,
"condition": { "op": "and", "children": [ { "field": "owner", "op": "=", "value": "@me" } ] },
"order_by": [ { "field": "date", "dir": "desc" } ],
"columns_override": [ … ],
"visible_if": { "roles": ["Sales Manager"], "condition": null }
}
order_by takes up to four entries, each asc or desc. A field may be a path (customer.customer_name).
Older layouts may carry filters — a flat list of [field, op, value] triples — instead of condition. Those still work and are rewritten as a condition the next time the tab is edited.
An element
{
"id": "el_status",
"type": "field",
"fieldname": "status",
"template": "{{ item_code }} × {{ qty }}", // wins over fieldname
"format": { "kind": "currency", "precision": 2 },
"prefix": { "text": "MR-" },
"empty_text": "—",
"mobile": "show",
"visible_if": { "roles": [], "condition": null },
"style_rules": [
{ "when": { "field": "status", "op": "=", "value": "Overdue" },
"style": { "pill": true, "bg": "red-100", "fg": "red-700" } },
{ "when": null, "style": { "pill": true, "bg": "gray-100" } }
]
}
Style rules are read in order and the first match wins; a rule with "when": null is the fallback and belongs last.
A related block
{
"type": "related",
"label": "Dispatch Orders",
"related": {
"target": "Dispatch Order",
"link_field": "sales_order",
"limit": 10,
"condition": { … }, // on the target
"filters": [ ["price_list", "=", "{{ selling_price_list }}"] ]
}
}
In filters, a value of {{ fieldname }} means "this row's value", and either side may be a path (price_list.currency).
What the validator enforces
- Every
idis unique across the layout — a tab cannot collide with a column. - Every fieldname exists on the DocType, unless the data source is a Server Script, in which case an unknown field is a warning rather than an error (the script may invent it).
- Enumerated values must be from the lists above.
- Numbers are bounded: widths, heights, font sizes,
limit(1–100),order_by(max 4), hop depth (max 10). - A condition must be one of the three accepted shapes, with a known operator, and a value unless the operator is
is set/is not set.
Errors block the save and name the path (columns[2].elements[0].fieldname). Warnings do not block — they appear next to the save.
Moving a layout between sites
Export writes the layout to a file; Import reads one back. The JSON panel is the same content if copying and pasting is easier. Only doctype_name has to match the target site — everything else is self-contained, though fields the target DocType does not have will fail validation on save, which is the point.