Conditional Styles & Advanced Formatting
Guide to the conditional styling system and advanced formatting options available for cards, tables, hierarchical tables, and note blocks.
This guide covers the conditional styling system available for card fields and table columns, and the advanced formatting options on note_block.
Overview
Conditional styles apply dynamic formatting (colors, icons, and backgrounds) based on field values. The two node types that consume conditionalStyles are card (per field) and table (per column, and only when the column is declared through columnManifest).
Core Concepts
Conditional Styles Structure
Each entry in a conditionalStyles array follows this shape:
{
"conditionalStyles": [
{
"value": "FAILED",
"icon": "circlealert",
"color": "#D32F2F",
"bgColor": "#FFEBEE",
"displayMode": "iconAndLabel",
"styleTarget": "cell",
"referenceField": null
}
]
}Available Properties
| Property | Type | Default | Description |
|---|---|---|---|
value | string | - | The value to match (case-insensitive, trimmed). Use "default" for fallback styling when no other rule matches |
icon | string | - | Icon key from the icon registry (for example, "check", "circlealert") |
color | string | - | Text or icon color (hex or theme token) |
bgColor | string | - | Background color (hex or theme token) |
displayMode | 'icon' | 'label' | 'iconAndLabel' | 'iconAndLabel' | Which elements to display |
styleTarget | 'cell' | 'icon' | 'text' | 'row' | 'cell' | Where to apply colors. 'row' also fills the adjacent label cell with bgColor in a table row - it is only meaningful on table columns |
referenceField | string | - | Look up the match value from a different field on the same row/card instead of this field's own value |
hidden | boolean | - | On a table column definition, hides the column from display while its data stays available to referenceField lookups on other columns |
Matching resolution: the first rule whose value equals the (possibly referenceField-redirected) value wins; if none match, a rule with "value": "default" is used as a fallback; otherwise no styling is applied.
Feature 1: styleTarget - Fine-Grained Styling Control
Control exactly which elements receive styling colors.
"styleTarget": "cell" (default)
Applies all styling to the entire cell:
- Icon gets the color
- Text gets the color
- Cell background gets
bgColor
{
"value": "SUCCESS",
"icon": "check",
"color": "#FFFFFF",
"bgColor": "#4CAF50",
"styleTarget": "cell"
}"styleTarget": "icon"
Applies the color only to the icon. Text and cell background stay at their defaults.
"styleTarget": "text"
Applies the color only to the text. Icon and cell background stay at their defaults.
"styleTarget": "row"
On a table column, also fills the row's label cell with bgColor. Only meaningful for table, not card.
Feature 2: referenceField - Cross-Column Styling
Apply styling to one column based on another column's value.
Use Case
You have a Status column with values like "FAILED", "SUCCESS", "PENDING", but you want to display Message text with icons styled based on the Status value, not the Message content.
Configuration
{
"key": "message",
"label": "Message",
"conditionalStyles": [
{
"value": "FAILED",
"icon": "circlealert",
"color": "#D32F2F",
"bgColor": "#FFEBEE",
"referenceField": "status",
"displayMode": "iconAndLabel"
},
{
"value": "SUCCESS",
"icon": "check",
"color": "#4CAF50",
"bgColor": "#E8F5E9",
"referenceField": "status"
}
]
}How It Works
- The renderer resolves the Message column's own value first.
referenceField: "status"tells it to look up the Status field on the same row instead.- The Status value is matched against this column's
conditionalStylesrules. - The matched rule's styling is applied to the Message cell.
Feature 3: hidden - Hide Columns While Keeping as Reference Source
On a table column declared through columnManifest, hidden: true removes the column from the rendered table while keeping its value available to other columns' referenceField lookups on the same row.
{
"key": "status",
"label": "Status",
"hidden": true
}Cards
card fields read conditionalStyles directly - a card does not need a columnManifest.
Card properties must be nested under "props", matching the Card reference:
{
"type": "card",
"props": {
"title": "License Status",
"fields": [
{
"key": "licenseStatus",
"label": "Status",
"value": "{{licenseStatus}}",
"conditionalStyles": [
{
"value": "EXPIRED",
"icon": "circlealert",
"color": "#D32F2F",
"styleTarget": "icon"
},
{
"value": "ACTIVE",
"icon": "check",
"color": "#4CAF50",
"styleTarget": "icon"
}
]
}
]
}
}Tables
Tables are the primary use case for conditional styling, but they need one extra layer that cards do not: a plain props.columns[] array with inline conditionalStyles is rendered by a simpler path that does not apply per-value cell styling. To get conditional styling on a table, declare the columns through props.columnManifest.columns[] instead. columnManifest also controls column order (displayOrder) and which columns are primary (always shown) versus overflow (primary: false).
Table with Conditional Styles
{
"type": "table",
"props": {
"title": "Systems Status",
"dataPath": "systems",
"columnManifest": {
"columns": [
{
"key": "system",
"label": "System",
"displayOrder": 0,
"width": "30%"
},
{
"key": "message",
"label": "Message",
"displayOrder": 1,
"width": "50%",
"conditionalStyles": [
{
"value": "FAILED",
"icon": "circlealert",
"color": "#D32F2F",
"bgColor": "#FFEBEE",
"styleTarget": "cell",
"referenceField": "status"
},
{
"value": "SUCCESS",
"icon": "check",
"color": "#4CAF50",
"bgColor": "#E8F5E9",
"styleTarget": "cell",
"referenceField": "status"
}
]
},
{
"key": "status",
"label": "Status",
"displayOrder": 2,
"hidden": true
}
]
}
}
}Default Styling
Use "value": "default" as fallback for unmatched values:
{
"conditionalStyles": [
{
"value": "PRIORITY",
"icon": "warning",
"color": "#FF9800"
},
{
"value": "default",
"icon": "info",
"color": "#999999"
}
]
}Hierarchical Tables
The hierarchical table node type is hierarchical_table (snake_case - not hierarchicalTable). It supports the same conditionalStyles shape on columnManifest columns as table. It has no parentColumn prop - the renderer does not read one; hierarchy comes from the nested dataSource structure. See Hierarchical Table for the full property reference.
{
"type": "hierarchical_table",
"props": {
"title": "Department Performance",
"dataSource": "{{departments}}",
"columnManifest": {
"columns": [
{ "key": "department", "label": "Department", "displayOrder": 0 },
{
"key": "status",
"label": "Status",
"displayOrder": 1,
"conditionalStyles": [
{ "value": "ON_TRACK", "icon": "status", "color": "#4CAF50", "styleTarget": "icon" },
{ "value": "AT_RISK", "icon": "circlealert", "color": "#FF9800", "styleTarget": "icon" },
{ "value": "OFF_TRACK", "icon": "status", "color": "#D32F2F", "styleTarget": "icon" }
]
},
{ "key": "healthScore", "label": "Health", "displayOrder": 2, "hidden": true }
]
}
}
}Note Block
note_block is a callout for a single highlighted message. It works differently from card and table conditional styling - there is no conditionalStyles array here, and several properties that look plausible are not read by the renderer.
Variants
The valid variant values are error, warning, success, info, important and neutral (the default). "danger" and "default" are not recognized values - an unrecognized variant falls back to neutral.
| Variant | Icon | Notes |
|---|---|---|
neutral (default) | info | Uses theme.secondary as its accent |
info | info | Uses theme.info |
success | check | Uses theme.success |
warning | warning | Uses theme.warning |
error | x | Uses theme.error |
important | circlealert | Fixed pale red accent, independent of theme |
The icon is fixed per variant. There is no icon prop on note_block - one is not read.
Content properties
By default (showVariantLabel unset or false), the block renders label: text, both read as static props:
{
"type": "note_block",
"props": {
"variant": "info",
"label": "System Update",
"text": "The system will be updated on 2026-09-25 from 2:00 PM to 4:00 PM EST"
}
}title and description are read only from the current _repeat item (_repeatItem.title / _repeatItem.description), never from a static props.title / props.description. A note_block that is not inside a _repeat loop cannot use title/description at all - use label/text instead, as above.
showVariantLabel: true changes the rendered format to VARIANT: label on the first line and the body text on the second line, still sourced from _repeatItem.title/_repeatItem.description when present, falling back to label/text otherwise:
{
"type": "note_block",
"props": {
"variant": "warning",
"label": "License Expiring",
"text": "Your license expires in 7 days",
"showVariantLabel": true
}
}Output: "WARNING: License Expiring" on line one, "Your license expires in 7 days" on line two.
bgColor, borderColor and textColor overrides are not read - colors always come from the variant. To use a different color, choose the closest variant rather than trying to override the color.
keepTogether (boolean, default true) controls whether the block is allowed to break across a page boundary; set it to false to allow a break.
Combining Note Blocks in Layout
Note blocks work as children of a section:
{
"type": "section",
"props": { "title": "System Status Report" },
"children": [
{
"type": "note_block",
"props": {
"variant": "info",
"label": "Report Generated",
"text": "Generated on 2026-09-22 at 14:30 UTC"
}
},
{
"type": "table",
"props": { "title": "System Details", "dataPath": "systems", "columnManifest": { "columns": [] } }
},
{
"type": "note_block",
"props": {
"variant": "warning",
"label": "Attention Required",
"text": "Review the failed systems above"
}
}
]
}Grid layout with a note block
The grid node type is grid_table (snake_case). Unlike the table nodes above, grid_table does not take a rows/columns/content structure - props.columns is the number of columns, and its children array is a flat list of nodes grouped into rows of that size:
{
"type": "grid_table",
"props": { "columns": 2, "headerRow": false },
"children": [
{
"type": "table",
"props": { "title": "Active Systems", "dataPath": "systems", "columnManifest": { "columns": [] } }
},
{
"type": "note_block",
"props": {
"variant": "success",
"label": "All Systems Operational",
"text": "18 systems running normally with no errors or warnings"
}
}
]
}Troubleshooting
Conditional Style Not Matching
- Check the value: Matching is case-insensitive, but spelling must match exactly.
- Check the table structure: on
tableandhierarchical_table,conditionalStylesonly take effect on columns declared insideprops.columnManifest.columns[]. A plainprops.columns[]array ignoresconditionalStyles. - Verify referenceField: if using
referenceField, ensure the referenced column key exists in the row data. - Try
"default": add a"value": "default"rule to catch unmatched cases.
Hidden Columns Not Referenced
- Ensure
referenceFieldpoints to the correct column key. - Hidden columns must still exist in the row data, even though they are not shown.
Icon Not Showing
- Icon keys must match the icon registry exactly (case-sensitive). An unrecognized key is dropped silently rather than raising an error.
Related Pages
- Card - field-level conditional styling
- Table - column-level conditional styling and
columnManifest - Hierarchical Table - multi-level tables with the same
columnManifestmechanism - Icon Reference - valid icon keys
Hierarchical Table
A multi-level adaptive table in REFRACT PDF. Renders deeply nested JSON arrays as progressive depth tables with per-level styling, overflow sub-rows, conditional cell styles, computations, and hierarchyRules-driven layout.
Conditional Visibility & Layout Collapse
How props.visible and expressions.visibleWhen hide a node, when to use each one, and how a layout_group recalculates column widths when a child is hidden.