> ## Documentation Index
> Fetch the complete documentation index at: https://learn.nextedy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Cell Decorators

> Cell decorators are JavaScript functions defined in the `cellDecorators` section of the sheet configuration.

export const LastReviewed = ({date}) => {
  if (!date) return null;
  const formatted = new Date(`${date}T00:00:00Z`).toLocaleDateString("en-US", {
    year: "numeric",
    month: "long",
    day: "numeric",
    timeZone: "UTC"
  });
  return <p className="mt-10 text-sm text-gray-400 dark:text-zinc-500 not-prose">
      Last reviewed on {formatted}
    </p>;
};

<Warning title="Use `toggleClass()` — Never Inline Styles">
  Cell decorators MUST apply styling through `$(info.cell).toggleClass()`. Direct inline styling via `info.cell.style.*` will BREAK because cells are reused during virtual scrolling — a class set inline on one row will leak into another row as the grid recycles DOM elements. Always toggle CSS classes by condition so that both the "on" and "off" states are explicit.
</Warning>

## Configuration

### cellDecorators Property

| Name             | Type     | Default | Description                                                                                                                                  |
| ---------------- | -------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
| `cellDecorators` | `object` | `{}`    | Maps decorator names to JavaScript function strings. Each function receives an `info` parameter and toggles CSS classes on the cell element. |

### styles Property

| Name     | Type     | Default | Description                                                                                                                                                                         |
| -------- | -------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `styles` | `object` | `{}`    | Maps CSS class selectors to CSS property blocks. Classes defined here are applied by cell decorator functions via `toggleClass`. Style values must be wrapped in curly braces `{}`. |

### Function Signature

```javascript theme={null}
function(info) {
  // info.value - the current cell value
  // info.cell  - the DOM element of the cell
  // info.item  - the current row's data object
}
```

| Parameter    | Type          | Description                                                                                                     |
| ------------ | ------------- | --------------------------------------------------------------------------------------------------------------- |
| `info.value` | `any`         | The display value of the current cell                                                                           |
| `info.cell`  | `HTMLElement` | The DOM element to apply CSS classes to using jQuery `$(info.cell)`                                             |
| `info.item`  | `object`      | The full work item data for the current row, providing access to any column value via `info.item['<bindings>']` |

<Warning title="Compare Against Enum IDs">
  Cell decorator functions compare against enum **IDs** (e.g., `'yes'`), not display values (e.g., `'Y'`). Always use the enum ID from your Polarion custom field configuration. Using the display value is a common source of non-working decorators.
</Warning>

## Applying CSS Classes

Use jQuery `toggleClass` to add or remove CSS classes based on conditions:

```javascript theme={null}
function(info) {
  var val = info.value;
  $(info.cell).toggleClass('className', condition);
}
```

The `toggleClass` method takes two parameters: the CSS class name and a boolean condition. When the condition is `true`, the class is added; when `false`, it is removed. You can chain multiple `toggleClass` calls to apply different classes based on different thresholds.

<Danger title="Cells Are Reused — Always Toggle, Never Assign">
  Nextedy RISKSHEET uses virtual scrolling, so cell DOM elements are recycled across rows as the user scrolls. If a decorator sets `info.cell.style.backgroundColor = 'red'` directly, that color will remain on the recycled cell when it is reused to display a different row. Always express styling as `toggleClass('className', condition)` so the class is removed when the condition is false.
</Danger>

<Tip title="Use `!important` for Style Overrides">
  CSS styles defined in the `styles` section often require the `!important` directive to override the default grid styling. Without `!important`, your custom background colors and text colors may not appear.
</Tip>

## Linking Decorators to Columns

Cell decorators are linked to columns in two ways.

### Automatic Matching by Column ID

When a decorator name in `cellDecorators` matches a column's `id` (or `bindings`), the decorator is automatically applied to that column. No additional configuration is needed:

```yaml theme={null}
columns:
  - id: rpn
    header: RPN
    type: int
    formula: commonRpn
cellDecorators:
  rpn: "function(info){ ... }"
```

### Explicit Assignment via cellRenderer

To apply a decorator to a column that does not share the decorator's name, use the column's `cellRenderer` property:

```yaml theme={null}
columns:
  - id: rpnInitial
    bindings: customField_rpnInitial
    header: Initial RPN
    cellRenderer: rpn
cellDecorators:
  rpn: "function(info){ ... }"
```

| Column Property | Type     | Default     | Description                                                                                                    |
| --------------- | -------- | ----------- | -------------------------------------------------------------------------------------------------------------- |
| `cellRenderer`  | `string` | `undefined` | Name of the cell decorator function to apply to this column. References a key in the `cellDecorators` section. |

## Built-In Decorator Patterns

### RPN Color Coding

Applies risk-level CSS classes based on RPN value thresholds. The example below uses 150 and 250 as the boundary values; thresholds are user-configurable per deployment and there is no product default — adjust them to match your scoring scheme.

```yaml theme={null}
cellDecorators:
  rpn: "function(info){ var val = info.value; $(info.cell).toggleClass('boldCol', true); $(info.cell).toggleClass('rpn1', val>0 && val<=150); $(info.cell).toggleClass('rpn2', val>150 && val<=250); $(info.cell).toggleClass('rpn3', val>250); }"
```

| CSS Class | Condition                 | Risk Level  | Background               | Text Color                      |
| --------- | ------------------------- | ----------- | ------------------------ | ------------------------------- |
| `boldCol` | Always applied            | All         | None                     | Bold weight (`font-weight:600`) |
| `rpn1`    | `val > 0 && val <= 150`   | Low risk    | `#eaf5e9` (light green)  | `#1d5f20` (dark green)          |
| `rpn2`    | `val > 150 && val <= 250` | Medium risk | `#fff3d2` (light yellow) | `#735602` (dark yellow)         |
| `rpn3`    | `val > 250`               | High risk   | `#f8eae7` (light red)    | `#ab1c00` (dark red)            |

<Frame>
  <img src="https://mintcdn.com/none-17b4493f/yWl5nA2D0IzEnZC1/risksheet/diagrams/reference/styling/cell-decorators/diagram-1.svg?fit=max&auto=format&n=yWl5nA2D0IzEnZC1&q=85&s=959a8ee2060b4d4f9a5bc74efe38db63" alt="diagram" style={{ maxWidth: "620px", width: "100%" }} width="620" height="100" data-path="risksheet/diagrams/reference/styling/cell-decorators/diagram-1.svg" />
</Frame>

### Row Header Decorator

Applies conditional styling to row headers based on the revised RPN value:

```yaml theme={null}
cellDecorators:
  rowHeaderRpnNew: "function(info){ var val = info.item['rpnNew']; $(info.cell).toggleClass('rpn1', val>0 && val<=150); $(info.cell).toggleClass('rpn2', val>150 && val<=250); $(info.cell).toggleClass('rpn3', val>250); }"
headers:
  rowHeader:
    renderer: rowHeaderRpnNew
```

<Note title="Row Header Renderer">
  To use a cell decorator on row headers, set `headers.rowHeader.renderer` to the decorator name. The row header decorator accesses `info.item['rpnNew']` instead of `info.value` because the row header cell does not have a direct binding to the RPN field. Row header decorators may also use `wijmo.toggleClass(info.cell, 'className', condition)` as an alternative to the jQuery syntax.
</Note>

### Enum Value Color Coding

Apply a background color when an enum field has a specific value:

```yaml theme={null}
cellDecorators:
  yesNoColor: "function(info){ var val = info.value; $(info.cell).toggleClass('greenBg', val === 'yes'); $(info.cell).toggleClass('redBg', val === 'no'); }"
styles:
  '.greenBg': '{background-color: #e8f5e9 !important; color: #2e7d32 !important;}'
  '.redBg': '{background-color: #ffebee !important; color: #c62828 !important;}'
```

### Severity-Based Color Coding

Apply graduated colors based on numeric severity ratings:

```yaml theme={null}
cellDecorators:
  severityColor: "function(info){ var val = info.value; $(info.cell).toggleClass('highSev', val >= 8); $(info.cell).toggleClass('medSev', val >= 4 && val < 8); $(info.cell).toggleClass('lowSev', val > 0 && val < 4); }"
styles:
  '.highSev': '{background-color: #ffcdd2 !important; color: #b71c1c !important;}'
  '.medSev': '{background-color: #fff9c4 !important; color: #f57f17 !important;}'
  '.lowSev': '{background-color: #c8e6c9 !important; color: #1b5e20 !important;}'
```

### String Prefix Matching

Decorators are not limited to numeric thresholds. The pattern below uses `String.startsWith` to color cells based on the prefix of an enum value, for example to visually distinguish "initial" assessments from later "additional" rounds:

```yaml theme={null}
cellDecorators:
  category: "function(info){ var val = ''+info.value; $(info.cell).toggleClass('rpn4', val.startsWith('additional')); $(info.cell).toggleClass('rpn5', val.startsWith('initial')); }"
```

## Advanced Patterns

### Conditional Read-Only Fields

Cell decorators can dynamically make cells non-editable by appending to the row's `systemReadOnlyFields`. This field is a **pipe-delimited string** on `info.item` (for example `'|severity||occurrence|'`); appending `'|fieldId|'` marks that cell read-only for the current row. Combine it with the built-in `rs-readonly` CSS class for grayed-out visual feedback:

```yaml theme={null}
cellDecorators:
  hazardClassificationDecorator: "(info) => { if (info.item['hazardClassification'] === 'QM') { info.item.systemReadOnlyFields += '|asilSeverity|'; info.item.systemReadOnlyFields += '|asilExposure|'; $(info.cell).addClass('rs-readonly'); } }"
```

| Concept        | Detail                                                                     |         |                                         |
| -------------- | -------------------------------------------------------------------------- | ------- | --------------------------------------- |
| Storage format | `info.item.systemReadOnlyFields` is a pipe-delimited string of field IDs   |         |                                         |
| Append syntax  | Concatenate \`'                                                            | fieldId | '\` — the pipes act as field boundaries |
| Visual styling | Apply the built-in `rs-readonly` class for the standard grayed-out look    |         |                                         |
| Scope          | Per-row, per-cell — different rows can lock different fields based on data |         |                                         |

**Use case.** In HARA, hazards classified as `QM` (non-safety) do not require detailed ASIL fields. The decorator locks `asilSeverity` and `asilExposure` for those rows while leaving them editable for `ASIL_B` and `ASIL_D` hazards.

<Info title="Verify in your environment">
  The `systemReadOnlyFields` pattern is an advanced runtime technique. Test in a non-production document before deploying — interactions with other decorators and validation rules should be reviewed.
</Info>

### Row Height Limiting

Limit row height for columns with long text content using a CSS max-height class:

```yaml theme={null}
cellDecorators:
  limitHeight: "function(info){ $(info.cell).toggleClass('maxHeightCell', true); }"
styles:
  '.maxHeightCell': '{max-height: 80px; overflow: hidden;}'
columns:
  - id: description
    header: Description
    cellRenderer: limitHeight
```

This applies a CSS class with `max-height` to cells via the `cellRenderer` column property. It is a styling workaround rather than a built-in row height property.

## Header Group Styles

The `styles` section also supports styling for column group header rows using compound selectors. Each style value must be wrapped in curly braces:

```yaml theme={null}
styles:
  '.firstRow .headSysReq': '{background-color: rgba(62, 175, 63, 0.12) !important; color: #2A792D !important;}'
  '.lastRow .headSysReq': '{background-color: #FFF !important; color: #2A792D !important;}'
  '.firstRow .headFinalRanking': '{background-color: rgba(62, 175, 63, 0.12) !important; color: #2A792D !important;}'
  '.lastRow .headFinalRanking': '{background-color: #FFF !important; color: #2A792D !important;}'
```

| Selector Pattern        | Description                                   |
| ----------------------- | --------------------------------------------- |
| `.firstRow .<groupCss>` | Styles the first header row of a column group |
| `.lastRow .<groupCss>`  | Styles the last header row of a column group  |

The `<groupCss>` value corresponds to the `headerGroupCss` property on the column definition.

## Style Property Reference

| Property           | Type     | Default | Description                                                                                                                 |
| ------------------ | -------- | ------- | --------------------------------------------------------------------------------------------------------------------------- |
| Style key format   | `string` | --      | CSS selector prefixed with `.` (e.g., `.rpn1`, `.boldCol`)                                                                  |
| Style value format | `string` | --      | CSS property block wrapped in `{}` (e.g., `'{font-weight: 600 !important;}'`). Styles may fail to apply without the braces. |

Standard CSS properties supported in `styles` include:

* `background-color` -- Cell background color
* `color` -- Text color
* `font-weight` -- Text weight (e.g., `600` for bold)
* `max-height` -- Maximum cell height (with `overflow: hidden`)
* `border` -- Cell border styling

## Comparison Mode Behavior

Cell decorators are **not applied** during comparison mode (baseline comparison view). In comparison mode, the grid uses its own highlighting system to show added, removed, and modified cells. Custom cell renderers are also disabled during comparison to prevent visual conflicts with the comparison indicators.

## Export Behavior

Cell decorator styles (background colors, text colors) are preserved when exporting to Excel and PDF formats (version 24.2.2+). The export process reads CSS colors from the rendered grid cells and converts them to the corresponding Excel fill/font colors or PDF styling.

## Interaction with Approval Review

Cell decorators are sometimes used to flag rows that are pending review or have been approved. Keep in mind:

<Note title="Approval review limitation">
  Risksheet approval review creates approval-tagged comments but does **not** trigger Polarion's formal approval workflow (draft → reviewed → approved). Decorators that visualize "approved" state are reading the Risksheet comment tag, not a Polarion workflow status — design your decorator conditions accordingly.
</Note>

## Complete Example

```yaml theme={null}
cellDecorators:
  rpn: "function(info){ var val = info.value; $(info.cell).toggleClass('boldCol', true); $(info.cell).toggleClass('rpn1', val>0 && val<=150); $(info.cell).toggleClass('rpn2', val>150 && val<=250); $(info.cell).toggleClass('rpn3', val>250); }"
  rowHeaderRpnNew: "function(info){ var val = info.item['rpnNew']; $(info.cell).toggleClass('rpn1', val>0 && val<=150); $(info.cell).toggleClass('rpn2', val>150 && val<=250); $(info.cell).toggleClass('rpn3', val>250); }"
  severityColor: "function(info){ var val = info.value; $(info.cell).toggleClass('highSev', val >= 8); $(info.cell).toggleClass('medSev', val >= 4 && val < 8); $(info.cell).toggleClass('lowSev', val > 0 && val < 4); }"
styles:
  '.boldCol': '{font-weight: 600 !important;}'
  '.rpn1': '{background-color: #eaf5e9 !important; color: #1d5f20 !important;}'
  '.rpn2': '{background-color: #fff3d2 !important; color: #735602 !important;}'
  '.rpn3': '{background-color: #f8eae7 !important; color: #ab1c00 !important;}'
  '.highSev': '{background-color: #ffcdd2 !important; color: #b71c1c !important;}'
  '.medSev': '{background-color: #fff9c4 !important; color: #f57f17 !important;}'
  '.lowSev': '{background-color: #c8e6c9 !important; color: #1b5e20 !important;}'
  '.firstRow .headSysReq': '{background-color: rgba(62, 175, 63, 0.12) !important; color: #2A792D !important;}'
  '.lastRow .headSysReq': '{background-color: #FFF !important; color: #2A792D !important;}'
headers:
  rowHeader:
    renderer: rowHeaderRpnNew
  columnHeader:
    height: 32
  columnGroupHeader:
    height: 32
formulas:
  commonRpn: "function(info){ var value = info.item['occ']*info.item['det']*info.item['sev']; return value?value:null; }"
  commonRpnNew: "function(info){ var value = info.item['occNew']*info.item['detNew']*info.item['sevNew']; return value?value:null; }"
```

## Related Pages

* [CSS Classes](/risksheet/reference/styling/css-classes) -- defining CSS class styles
* [Conditional Formatting](/risksheet/reference/styling/conditional-formatting) -- combining decorators with formulas
* [Item Colors](/risksheet/reference/styling/item-colors) -- row-level color coding
* [Formula Examples](/risksheet/reference/formulas/formula-examples) -- formulas that drive decorator values
* [Sheet Configuration Format](/risksheet/reference/configuration/risksheet-json-format) -- complete configuration file reference

<LastReviewed date="2026-06-18" />
