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

# Server Render Columns

> Server render columns display read-only content generated by server-side Velocity scripts.

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

## Overview

`serverRender` enables server-side rendering of complex linked item traversals and computed data using Apache Velocity. When this property is set on a column, the configuration manager automatically forces the column data type to `text` and sets `readOnly` to `true` — the column becomes a read-only text column whose content is generated by the Velocity template each time the grid loads. This pattern is essential for multi-level link traversals, rich-text rendering with embedded images, and any computed display that would be impractical to express with client-side formulas alone.

| Aspect           | Detail                                                                  |
| ---------------- | ----------------------------------------------------------------------- |
| Column type      | Automatically set to `text` when `serverRender` is defined              |
| Editability      | Always `readOnly: true` (set automatically)                             |
| Rendering engine | Apache Velocity on the Polarion server                                  |
| Output format    | HTML rendered in cell; plain text fallback for exports                  |
| Binding          | Optional; used as column `id` if `id` is not specified                  |
| Performance      | Evaluated per row on each grid load; complex scripts increase load time |

<Frame>
  <img src="https://mintcdn.com/none-17b4493f/yWl5nA2D0IzEnZC1/risksheet/diagrams/reference/columns/server-render-columns/diagram-1.svg?fit=max&auto=format&n=yWl5nA2D0IzEnZC1&q=85&s=149601e9c2219e7fba991d6cffc42c89" alt="diagram" style={{ maxWidth: "700px", width: "100%" }} width="700" height="160" data-path="risksheet/diagrams/reference/columns/server-render-columns/diagram-1.svg" />
</Frame>

<Note title="Automatic Read-Only Behavior">
  When `serverRender` is set on a column definition, the configuration manager automatically forces the column type to `text` and sets `readOnly` to `true`. You do not need to specify these properties manually. This behavior is enforced server-side and cannot be overridden. Text wrapping inside server-rendered cells is controlled through the `styles` section of the sheet configuration using standard CSS rules — there is no column-level text-wrapping property.
</Note>

## Column Definition Properties

| Property       | Type      | Default                                    | Description                                                                                                                                                                                                                                 |
| -------------- | --------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`           | `string`  | Auto-generated from `header` or `bindings` | Unique identifier for the column. Must be unique across all columns in the configuration.                                                                                                                                                   |
| `header`       | `string`  | None                                       | Display text shown in the column header.                                                                                                                                                                                                    |
| `serverRender` | `string`  | None                                       | Velocity template expression executed on the server to produce cell HTML content. When set, overrides normal data binding.                                                                                                                  |
| `type`         | `string`  | `text` (forced)                            | Automatically set to `text` when `serverRender` is present. Cannot be changed.                                                                                                                                                              |
| `readOnly`     | `boolean` | `true` (forced)                            | Automatically set to `true` when `serverRender` is present. Cannot be changed.                                                                                                                                                              |
| `level`        | `number`  | `1`                                        | Visual hierarchy level for cell merging (1-indexed; maps to entries in the `levels` array). An unleveled risk-item column defaults to level 1 and merges into the first level. Task columns are a separate axis and have no level assigned. |
| `width`        | `number`  | See application                            | Column width in pixels.                                                                                                                                                                                                                     |
| `minWidth`     | `number`  | See application                            | Minimum width in pixels the column can be resized to.                                                                                                                                                                                       |
| `headerGroup`  | `string`  | None                                       | Name of the header group this column belongs to for multi-level column headers.                                                                                                                                                             |
| `collapseTo`   | `boolean` | `false`                                    | When `true`, this column remains visible when its header group is collapsed.                                                                                                                                                                |
| `filterable`   | `boolean` | `true`                                     | Controls whether users can filter the grid by values in this column.                                                                                                                                                                        |
| `cellCss`      | `string`  | None                                       | CSS class applied to cells in this column. Use this together with named styles in the sheet configuration to control text wrapping, font, and other presentation.                                                                           |
| `headerCss`    | `string`  | None                                       | CSS class applied to the column header cell.                                                                                                                                                                                                |

### `typeProperties` Sub-properties

When a server render column is used together with an itemLink-style binding (for example, `bindings: task.$item`), the same `typeProperties` block used by link columns applies. These sub-properties control how linked items are resolved before the Velocity template runs.

| Sub-property    | Type      | Description                                                                                                  |
| --------------- | --------- | ------------------------------------------------------------------------------------------------------------ |
| `linkRole`      | `string`  | Link role ID connecting the current item to the target item (for example, `relates_to`, `verifies`).         |
| `linkTypes`     | `string`  | Comma-separated list of target work item type IDs (for example, `requirement,testcase`).                     |
| `linkDirection` | `string`  | Set to `back` to traverse the link in the reverse direction.                                                 |
| `backLink`      | `boolean` | When `true`, the column renders back-links from the linked items toward the current item.                    |
| `itemTemplate`  | `string`  | Reference to a Velocity template that renders each linked item.                                              |
| `queryFactory`  | `string`  | Reference to a named entry in the `queryFactories` section used to further filter the resolved linked items. |

## Velocity Context Variables

The `serverRender` script has access to Polarion's Velocity context. The most commonly used variables for server render columns are:

| Variable                 | Type          | Description                                                                                                                                                                                                           |
| ------------------------ | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `$item`                  | Work Item     | The current Polarion work item object for the row being rendered. Provides access to fields, links, attachments, metadata, and project context.                                                                       |
| `$transaction`           | Transaction   | The current Polarion transaction. Used for cross-entity lookups (for example, `$transaction.testRuns().getBy().oldApiObject(...)`).                                                                                   |
| `$testManagementService` | Service       | Polarion Test Management service. Provides access to test execution records via `$testManagementService.getLastTestRecords($item.getOldApi(), N)`, which returns the last `N` test records for the current work item. |
| `$config`                | Configuration | Configuration properties defined at the document or project level. Accessed via `$config.get('propertyKey')`.                                                                                                         |

### Velocity Syntax: Property Access vs Method Calls

`serverRender` accepts both Velocity syntax flavours interchangeably:

* **Property access (no parentheses)** — chains field navigation directly:
  ```velocity theme={null}
  $item.fields.description.render.htmlFor().forFrame()
  ```
* **Method-call syntax (with parentheses)** — uses explicit method invocation:
  ```velocity theme={null}
  $item.fields().attachments().iterator()
  ```

Both patterns resolve to the same underlying API. Choose whichever style matches the surrounding template; mixing them in the same expression is allowed and common in real configurations.

## Basic Configuration

A minimal server render column in the sheet configuration:

```yaml theme={null}
columns:
  - id: descriptionRendered
    header: Description
    serverRender: "$item.fields().get('description').render().htmlFor().forFrame()"
```

This column renders the `description` field as full HTML, preserving formatting, links, and embedded images. The column is automatically read-only.

## Common Patterns

### Rendering Rich Text Fields with Clickable Links

Rich text fields (description, custom HTML fields) display as plain text in standard columns. Use `serverRender` to render the full HTML including clickable hyperlinks, text formatting, and colors:

```yaml theme={null}
- id: descHtml
  header: Description
  serverRender: "$item.fields().get('description').render().htmlFor().forFrame()"
```

The general pattern for any rich text field follows the same structure. Replace the field ID with your target field:

```yaml theme={null}
- id: notesRendered
  header: Notes
  serverRender: "$item.fields().get('customFieldNotes').render().htmlFor().forFrame()"
```

<Tip title="Rich Text with Embedded Images">
  Rich text fields that contain embedded images (such as symbol libraries, diagrams, or screenshots) render inline in the cell using this pattern. If images appear truncated, you can control the display size via CSS in the Top Panel template. When using images from rich text fields, ensure the column width is sufficient to display the image content legibly.
</Tip>

### Custom Redirect Links

Construct clickable links that navigate to specific Polarion pages, external URLs, or other risksheet documents:

```yaml theme={null}
- id: openItem
  header: Open
  serverRender: "<a href='/polarion/#/project/$item.getProjectId()/workitem?id=$item.getId()' target='_blank'>$item.getId()</a>"
```

You can also construct redirect links to arbitrary paths:

```yaml theme={null}
- id: customLink
  header: Link
  serverRender: "<a href='/polarion/redirect/project/$item.getProjectId()/wiki/Requirements/$item.getId()' target='_blank'>View Requirement</a>"
```

### Displaying Indirectly Linked Work Items

For multi-level linked work items (Level 0 -> Level 1 -> Level 2), where you need to traverse intermediate links to display items that are not directly linked to the current row:

```yaml theme={null}
- id: indirectReqs
  header: Linked Requirements
  serverRender: |
    #foreach($link in $item.getLinkedWorkItems())#if($link.getRole().getId() == 'relates_to')#set($linked = $link.getOppositeObject())$linked.getId(): $linked.getTitle()<br/>#end#end
```

Real aerospace configurations chain three levels of traversal in a single `serverRender` expression (risk -> task -> requirement -> testcase). The same `#foreach` over `$item.getLinkedWorkItems()` is nested and filtered by `linkRole` at each level.

<Warning title="Read-Only Limitation">
  Server render columns displaying indirectly linked work items are always read-only. For editable multi-level linking, consider the `upstreamChains` configuration property (format: `fromType-linkRole-toType`), which automatically creates transitive link chains. Note that `upstreamChains` only creates links and never deletes them.
</Warning>

### Horizontal Line Separators Between Items

When rendering multiple linked items in a single cell, use `<hr/>` tags to provide visual separation:

```yaml theme={null}
- id: linkedItems
  header: Linked Items
  serverRender: |
    #foreach($link in $item.getLinkedWorkItems())#if($foreach.count > 1)<hr/>#end$link.getOppositeObject().getTitle()#end
```

### Test Execution Records

Use `$testManagementService` to display the latest test execution result for a work item. `$testManagementService.getLastTestRecords($item.getOldApi(), N)` returns up to `N` test records for the current item; `$transaction` is used to resolve the test run reference:

```yaml theme={null}
- id: lastTestResult
  header: Last Test Result
  serverRender: |
    #macro(getLastTestRecord $item)
      #set($testRecords = $testManagementService.getLastTestRecords($item.getOldApi(), 1))
      #foreach($iRecord in $testRecords)
        #set($testRun = $transaction.testRuns().getBy().oldApiObject($iRecord.getTestRun()))
        $iRecord.getTestRun().getId() - $iRecord.getResult().name
      #end
    #end
    #getLastTestRecord($item)
```

The available variables in this pattern are `$item` (current work item), `$transaction` (current Polarion transaction, used to resolve cross-entity references), and `$testManagementService` (test management service entry point).

### Rendering Work Item Attachments

`serverRender` can iterate the attachments of a work item using the method-call API surface and emit a clickable link for each one. The attachment URL is generated by chaining `.url().linkToOpen().toEncodedRelativeUrl('')`:

```yaml theme={null}
- id: attachments
  header: Attachments
  serverRender: |
    #foreach($a in $item.fields().attachments().iterator())
      <a target='blank' href='$a.fields().url().linkToOpen().toEncodedRelativeUrl("")'>
        $a.render().htmlFor().forFrame()
      </a>
    #end
```

Each attachment is rendered through `.render().htmlFor().forFrame()`, which produces an inline HTML representation suitable for display inside the cell.

### Outline Number Sorting

To sort risksheet items by their LiveDoc outline number (so that `1.2.10` sorts after `1.2.2`), create a server render column that zero-pads each segment of the outline number, then reference the column in the `sortBy` property:

```yaml theme={null}
columns:
  - id: outlineSort
    header: Outline #
    serverRender: |
      #set($on = $item.getOutlineNumber())#foreach($seg in $on.split('\\.'))#set($padded = "000$seg")$padded.substring($padded.length() - 4)#if($foreach.hasNext).#end#end
sortBy:
  - outlineSort
```

Without zero-padding, string comparison sorts `1.10.1` before `1.2.2`. With padding, `0001.0002.0002` correctly sorts before `0001.0010.0001`.

| Input (raw) | Velocity Output (padded) | Sort Position |
| ----------- | ------------------------ | ------------- |
| 1.2.2       | 0001.0002.0002           | 1st           |
| 1.2.10      | 0001.0002.0010           | 2nd           |
| 1.10.1      | 0001.0010.0001           | 3rd           |
| 2.1.1       | 0002.0001.0001           | 4th           |

### Multi-Project Configuration Properties

When defining server render columns that reference configuration properties across multiple projects, use `$config` Velocity variables. Space-separated project IDs can be referenced with separate `$config` lookups:

```yaml theme={null}
- id: crossProjectData
  header: External Data
  serverRender: "$config.get('customPropertyKey')"
```

<Warning title="Empty Configuration Property Values">
  When using configuration properties to define multi-project upstream columns, empty property values after the `=` sign cause errors. The alternative project must use a direct project ID, not another configuration property variable. Always ensure configuration property values are non-empty.
</Warning>

## Export Behavior

Server render columns produce HTML in the interactive grid. During exports, this HTML is converted to plain text:

| Export Type | Conversion Logic                                                                                                                                  | Result                                |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- |
| **Excel**   | HTML tags are stripped using text extraction. `</li>` tags are converted to newlines before stripping, preserving list structure.                 | Plain text with line breaks for lists |
| **PDF**     | The `mainSheetCellFormatter` strips HTML content to plain text. Server-rendered HTML is processed through the same formatter as other cell types. | Plain text in PDF cells               |

<Info title="Verify in application">
  The exact HTML-to-text conversion depends on the complexity of your Velocity output. Nested tables, complex CSS, or JavaScript in server render output may not convert cleanly to plain text exports. Test your specific scripts with both Excel and PDF exports.
</Info>

### PDF Export Considerations

When exporting to PDF via custom `pdfscript.js`, server render columns are handled by the `renderDataCell` function, which detects columns with `serverRender` defined and applies HTML-to-text stripping. The `emptyPlaceholder` property (configurable in custom export scripts) controls what text appears for null or empty server render output in the PDF.

## Interaction with Other Column Properties

| Property         | Interaction with `serverRender`                                                                                                                                                                                                                                                                                                                 |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `formula`        | **Mutually exclusive.** Do not combine `serverRender` and `formula` on the same column. `formula` runs client-side JavaScript; `serverRender` runs server-side Velocity. If both are set, `serverRender` takes precedence (the column type is forced to `text`).                                                                                |
| `bindings`       | **Optional.** When `serverRender` is set, the column does not bind to a data field for display. If `bindings` is provided, it is used only as the default column `id` when `id` is not explicitly specified. The `$item` suffix pattern (`bindings: task.$item`) gives the Velocity template access to the linked item's full work item object. |
| `cellDecorators` | **Compatible.** Cell decorators can be applied to server render columns. The decorator function receives the rendered text value in `info.value` and the cell DOM element in `info.cell`.                                                                                                                                                       |
| `sortBy`         | **Compatible.** Server render column IDs can be referenced in the global `sortBy` array for default sort ordering. Sorting uses the text output of the Velocity expression.                                                                                                                                                                     |
| `views`          | **Compatible.** Server render columns participate in saved view column visibility toggling just like any other column type.                                                                                                                                                                                                                     |
| `headerGroup`    | **Compatible.** Server render columns can be grouped under header groups and support `collapseTo` behavior.                                                                                                                                                                                                                                     |

## Complete Example

A full sheet configuration demonstrating multiple server render column patterns in an automotive FMEA context:

```yaml theme={null}
columns:
  - id: systemItemId
    header: ID
    bindings: systemItemId
    level: 1
    width: 80
  - id: title
    header: Failure Mode
    bindings: title
    level: 1
    width: 200
  - id: descRendered
    header: Description (Rich Text)
    serverRender: "$item.fields().get('description').render().htmlFor().forFrame()"
    level: 1
    width: 280
    headerGroup: Failure Details
  - id: outlineSort
    header: Outline #
    serverRender: |
      #set($on = $item.getOutlineNumber())#foreach($seg in $on.split('\\.'))#set($padded = "000$seg")$padded.substring($padded.length() - 4)#if($foreach.hasNext).#end#end
    level: 1
    width: 100
  - id: linkedReqs
    header: Requirements
    serverRender: |
      #foreach($link in $item.getLinkedWorkItems())#if($link.getRole().getId() == 'verifies')#set($req = $link.getOppositeObject())$req.getId()<br/>#end#end
    level: 1
    width: 150
    headerGroup: Traceability
  - id: riskCategory
    header: Risk Category
    serverRender: "$item.fields().get('riskCategory').render().htmlFor().forFrame()"
    level: 1
    width: 130
    headerGroup: Assessment
  - id: openInPolarion
    header: Open
    serverRender: "<a href='/polarion/#/project/$item.getProjectId()/workitem?id=$item.getId()' target='_blank'>Open</a>"
    level: 1
    width: 60
sortBy:
  - outlineSort
levels:
  - name: Failure mode
    controlColumn: systemItemId
    zoomColumn: title
dataTypes:
  risk:
    type: fmea_risk
    role: has_risk
  task:
    type: fmea_task
    role: mitigates
```

## See Also

* [Column Type Reference](/risksheet/reference/columns/column-types) -- overview of all available column types
* [Calculated Columns](/risksheet/reference/columns/calculated-columns) -- client-side formula alternative to server-side rendering
* [Rich Text Fields](/risksheet/reference/columns/rich-text-fields) -- rendering rich text content in columns
* [Velocity Template Context](/risksheet/reference/api/velocity-context) -- full Velocity context variable reference
* [Custom Renderer Templates](/risksheet/reference/templates/custom-renderers) -- advanced rendering templates for row headers and cells
* [Configuration Properties Index](/risksheet/reference/configuration/properties-index) -- complete property reference
* [Levels Configuration](/risksheet/reference/levels-configuration) -- hierarchical level definitions

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