> ## 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.

# Create Custom Renderers

> Register custom JavaScript rendering functions to control how individual cells and row headers display data in the Nextedy RISKSHEET grid.

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>;
};

Risksheet provides two distinct customization mechanisms that are often confused:

* **Cell decorators** — JavaScript functions that toggle CSS classes on cells. Functions live in the `cellDecorators` section of the sheet configuration; columns reference them via the `cellRenderer` property.
* **Custom cell renderers** — JavaScript functions that replace cell HTML content entirely. Functions live in the `cellRenderers` section of the sheet configuration; columns also reference them via the `cellRenderer` property.

Both mechanisms are configured in the sheet configuration file, edited through the YAML editor available in Polarion (v25.5.0+).

<Steps>
  <Step title="Define a Cell Decorator Function">
    Cell decorators are JavaScript functions registered in the `cellDecorators` section of the sheet configuration. Each function receives an `info` object and uses jQuery to toggle CSS classes on the cell element based on data values.

    The `info` object provides:

    | Property     | Type          | Description                                                              |
    | ------------ | ------------- | ------------------------------------------------------------------------ |
    | `info.cell`  | `HTMLElement` | The DOM element of the cell being rendered                               |
    | `info.item`  | `object`      | The current row's data object (access fields via `info.item['fieldId']`) |
    | `info.value` | `any`         | The cell's current value                                                 |

    Add a decorator to the `cellDecorators` section:

    ```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); }"
    ```

    This example applies CSS classes based on RPN (Risk Priority Number) value thresholds:

    * `boldCol` — always applied (bold text)
    * `rpn1` — applied when value is 1 to 150 (low risk)
    * `rpn2` — applied when value is 151 to 250 (medium risk)
    * `rpn3` — applied when value exceeds 250 (high risk)

    The thresholds shown above are illustrative — RPN thresholds are user-configurable in cellDecorators and vary per deployment; pick values that match your project's risk-acceptance criteria.

    <Tip title="Always Use toggleClass">
      Cell decorators MUST use `$(info.cell).toggleClass()` rather than directly setting inline styles. The grid reuses DOM cells when scrolling, so classes set with `toggleClass` are properly added and removed as rows recycle. Inline styles set with `.css()` will persist on the recycled cell and corrupt the display of unrelated rows.
    </Tip>

    <Note title="Multiple Decorators">
      You can define as many named decorators as needed in the `cellDecorators` object. Each column can reference a different decorator via the `cellRenderer` property.
    </Note>
  </Step>

  <Step title="Define Matching CSS Styles">
    Create CSS class definitions in the `styles` section of the sheet configuration to define the visual appearance applied by your decorators. Style names must be valid CSS selectors prefixed with a dot, and the rule body MUST be wrapped in braces:

    ```yaml theme={null}
    styles:
      ".boldCol": "{font-weight:600;}"
      ".rpn1": "{background-color: #eaf5e9 !important; color: #1d5f20 !important;}"
      ".rpn2": "{background-color: #fff3d2 !important; color: #735602 !important;}"
      ".rpn3": "{background-color: #f8eae7 !important; color: #ab1c00 !important;}"
    ```

    | CSS Class  | Risk Level       | Background Color         | Text Color              | Description                   |
    | ---------- | ---------------- | ------------------------ | ----------------------- | ----------------------------- |
    | `.boldCol` | All              | —                        | —                       | Bold font weight for emphasis |
    | `.rpn1`    | Low (1–150)      | `#eaf5e9` (light green)  | `#1d5f20` (dark green)  | Acceptable risk               |
    | `.rpn2`    | Medium (151–250) | `#fff3d2` (light yellow) | `#735602` (dark yellow) | Review recommended            |
    | `.rpn3`    | High (>250)      | `#f8eae7` (light red)    | `#ab1c00` (dark red)    | Mitigation required           |

    <Tip title="Use `!important` for Background and Text Colors">
      Always use `!important` on `background-color` and `color` properties in cell decorator styles. Without `!important`, the grid's default cell styling may override your conditional formatting.
    </Tip>
  </Step>

  <Step title="Apply Decorators to Columns">
    Reference your decorator on a column using the `cellRenderer` property. The value is the name of a function in the `cellDecorators` section. This activates the decorator for all cells in that column:

    ```yaml theme={null}
    columns:
      - id: rpn
        bindings: rpn
        header: RPN
        formula: commonRpn
        cellRenderer: rpn
      - id: rpnNew
        bindings: rpnNew
        header: RPN (New)
        formula: commonRpnNew
        cellRenderer: rpn
    ```

    The same decorator can be applied to multiple columns. In the example above, both the initial RPN and the revised RPN columns use the same `rpn` decorator for consistent color coding.

    <Info title="cellRenderer Points Into cellDecorators">
      The column-level property is named `cellRenderer`, but the function it references is registered in the `cellDecorators` section of the sheet configuration. This is the standard pattern verified in production configurations and KB article #48001172969 — the column property and the registration section have different names by design.
    </Info>
  </Step>

  <Step title="Configure a Row Header Renderer">
    Use `headers.rowHeader.renderer` to apply conditional styling to the row header (the leftmost column showing row numbers). The renderer references a function registered in the `cellDecorators` section. Row header decorators use the same `$(info.cell).toggleClass(...)` jQuery form as cell decorators, which is what the product's reference templates use:

    ```yaml theme={null}
    headers:
      rowHeader:
        renderer: rowHeaderRpnNew
    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); }"
    ```

    The row header renderer accesses `info.item` to read any property from the row's work item. In this example, it reads the revised RPN value (`rpnNew`) to color the row header based on the post-mitigation risk level, providing at-a-glance risk assessment for each row.

    **Row Header Rendering Flow:**

    headers.rowHeader.renderer       cellDecorators.rowHeaderRpnNew        styles.rpn1 / rpn2 / rpn3
    ──────────────────────────  ─►   ──────────────────────────────  ─►   ───────────────────────────
    references decorator name        function evaluates row data            CSS classes applied to cell
  </Step>

  <Step title="Register Custom Cell Renderers">
    For complete control over cell display — replacing the default rendering entirely rather than adding CSS classes — register custom cell renderer functions in the `cellRenderers` section of the sheet configuration. Custom cell renderers differ from cell decorators:

    | Feature              | Cell Decorators                             | Custom Cell Renderers              |
    | -------------------- | ------------------------------------------- | ---------------------------------- |
    | Purpose              | Add/remove CSS classes on the existing cell | Replace cell HTML content entirely |
    | Registration section | `cellDecorators`                            | `cellRenderers`                    |
    | Column property      | `cellRenderer`                              | `cellRenderer`                     |
    | Parameters           | `info` (cell, item, value)                  | grid, cell, item, value            |
    | Comparison mode      | Disabled                                    | Disabled                           |

    The column-level property name is the same in both cases (`cellRenderer`), but the function it points to lives in a different registration namespace. Risksheet resolves the reference by looking up the function name in both sections.

    Custom renderers receive four parameters and can modify the cell appearance completely:

    ```yaml theme={null}
    cellRenderers:
      statusIcon: "function(grid, cell, item, value){ cell.innerHTML = value === 'open' ? '<span class=\"status-open\">Open</span>' : '<span class=\"status-closed\">Closed</span>'; }"
    ```

    Reference the renderer on a column:

    ```yaml theme={null}
    columns:
      - id: riskStatus
        bindings: riskStatus
        header: Status
        cellRenderer: statusIcon
    ```

    <Warning title="Custom Renderers Are Disabled During Comparison Mode">
      When comparing against a baseline revision, custom cell renderers are not applied. The comparison highlighting takes precedence to clearly show changes between revisions. Plan your renderers knowing that comparison mode will display raw values.
    </Warning>

    <Info title="Two Registration Namespaces, One Column Property">
      `cellDecorators` and `cellRenderers` are distinct registration sections — they are not the same namespace. If you give a decorator and a renderer the same name, the column's `cellRenderer` reference will resolve to one of them depending on lookup order. Use descriptive, distinct names to avoid ambiguity (e.g., `rpn` for decorators, `statusIcon` for renderers).
    </Info>
  </Step>

  <Step title="Style Column Group Headers">
    Use styles with `.firstRow` and `.lastRow` selectors to differentiate column group header appearance. This is useful when organizing columns into header groups:

    ```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;}"
    ```

    Apply the CSS class to a column's header group:

    ```yaml theme={null}
    columns:
      - id: sysReq
        header: System Requirement
        headerGroup: Upstream
        headerGroupCss: headSysReq
    ```

    <Tip title="Column Header Group Styling">
      Use `.firstRow` and `.lastRow` selectors to differentiate the top and bottom rows of multi-level column group headers. The `.firstRow` selector targets the group header row, while `.lastRow` targets the individual column header row beneath the group.
    </Tip>
  </Step>
</Steps>

## Complete Configuration Example

A full sheet configuration snippet combining cell decorators, styles, row header renderer, and column configuration:

```yaml theme={null}
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; }"

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); }"

styles:
  ".boldCol": "{font-weight:600;}"
  ".rpn1": "{background-color: #eaf5e9 !important; color: #1d5f20 !important;}"
  ".rpn2": "{background-color: #fff3d2 !important; color: #735602 !important;}"
  ".rpn3": "{background-color: #f8eae7 !important; color: #ab1c00 !important;}"

headers:
  rowHeader:
    renderer: rowHeaderRpnNew
  columnHeader:
    height: 32

columns:
  - id: rpn
    header: RPN
    bindings: rpn
    formula: commonRpn
    cellRenderer: rpn
    level: 2
    headerGroup: Initial Assessment
  - id: rpnNew
    header: RPN (New)
    bindings: rpnNew
    formula: commonRpnNew
    cellRenderer: rpn
    level: 2
    headerGroup: Final Ranking
```

## Verification

You should now see:

* RPN cells colored green, yellow, or red based on their calculated values
* Bold text applied to all RPN cells via the `boldCol` class
* Row headers colored according to the revised RPN value for at-a-glance risk assessment
* Column group headers with differentiated styling for first and last rows (if configured)
* No JavaScript errors in the browser developer console (`F12`)

Open the browser developer tools and inspect a cell element to verify that the expected CSS classes (e.g., `rpn1`, `boldCol`) are present on the cell's DOM element.

## See Also

* [Apply Conditional Formatting](/risksheet/guides/styling/conditional-formatting) — broader conditional formatting patterns beyond cell decorators
* [Configure Cell Styles](/risksheet/guides/styling/cell-styles) — CSS style definition reference
* [Configure Row Header Styles](/risksheet/guides/styling/row-header-styles) — row header customization options
* [Render Custom Data](/risksheet/guides/columns/custom-data-rendering) — data rendering patterns for columns
* [Cell Decorators](/risksheet/reference/styling/cell-decorators) — reference documentation for cell decorators
* [Conditional Formatting](/risksheet/reference/styling/conditional-formatting) — conditional formatting reference
* [Custom Renderer Templates](/risksheet/reference/templates/custom-renderers) — template reference for renderers

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