Skip to main content

Prerequisites

Before creating custom renderers, ensure you have:
  • Administrative access to edit RISKSHEET configuration
  • Basic JavaScript and jQuery knowledge
  • Familiarity with RISKSHEET configuration structure

Step 1: Define the Renderer Function

Edit your risksheet.json configuration and add a custom renderer function to the cellDecorators section:
"cellDecorators": {
  "statusHighlight": "function(info) { var status = info.item.status; if(status === 'open') { $(info.cell).css('background-color', '#ffebee'); $(info.cell).css('font-weight', 'bold'); } else if(status === 'closed') { $(info.cell).css('background-color', '#e8f5e9'); } }"
}
The renderer function receives an info object containing:
  • info.cell - jQuery-wrapped DOM element for the cell
  • info.item - Work item data object with all field values
  • info.value - The cell’s bound value
  • info.grid - Reference to the FlexGrid control

Step 2: Apply Renderer to Column

Reference the custom renderer in a column definition using the cellRenderer property:
{
  "id": "status",
  "header": "Status",
  "type": "enum:status",
  "cellRenderer": "statusHighlight"
}

Step 3: Add Supporting CSS (Optional)

For more maintainable styling, define CSS classes in the styles section and toggle them in your renderer:
"styles": {
  ".status-open": "background-color: #ffebee; font-weight: bold;",
  ".status-closed": "background-color: #e8f5e9;",
  ".status-pending": "background-color: #fff9c4;"
},
"cellDecorators": {
  "statusHighlight": "function(info) { $(info.cell).removeClass('status-open status-closed status-pending'); $(info.cell).addClass('status-' + info.item.status); }"
}

Common Renderer Patterns

Conditional Icon Display

Add icons based on field values:
"iconRenderer": "function(info) { 
  var priority = info.item.priority; 
  var icon = ''; 
  if(priority === 'high') icon = ' '; 
  $(info.cell).html(icon + info.value); 
}"

Multi-Field Conditional Formatting

Style cells based on multiple field values:
"riskRenderer": "function(info) { 
  var sev = info.item.severity; 
  var occ = info.item.occurrence; 
  var risk = sev * occ; 
  $(info.cell).toggleClass('high-risk', risk > 15); 
  $(info.cell).toggleClass('medium-risk', risk > 8 && risk <= 15); 
  $(info.cell).toggleClass('low-risk', risk <= 8); 
}"

Dynamic Readonly Control

Make cells readonly based on conditions:
"conditionalReadonly": "function(info) { 
  var locked = info.item.locked; 
  if(locked === 'yes') { 
    if(!info.item.systemReadOnlyFields) info.item.systemReadOnlyFields = []; 
    if(info.item.systemReadOnlyFields.indexOf('mitigation') === -1) { 
      info.item.systemReadOnlyFields.push('mitigation'); 
    } 
    $(info.cell).addClass('readonly'); 
  } 
}"
Cell renderers execute during grid rendering and cell updates. Avoid expensive operations like API calls or complex calculations that could impact performance. For formula-driven values, use calculated columns instead.

Renderer Information Flow

diagram

Advanced Techniques

Row Header Rendering

Customize row headers using the headers.rowHeader.renderer property:
"headers": {
  "rowHeader": {
    "renderer": "rowRiskLevel"
  }
},
"cellDecorators": {
  "rowRiskLevel": "function(info) { var rpn = info.item.rpn; $(info.cell).toggleClass('rpn-high', rpn > 100); $(info.cell).toggleClass('rpn-medium', rpn > 50 && rpn <= 100); $(info.cell).toggleClass('rpn-low', rpn <= 50); }"
}

HTML Content Injection

Render custom HTML structures:
"linkWithIcon": "function(info) { 
  if(!info.value) return; 
  var html = '<div class=\"custom-link\">'; 
  html += '<span class=\"icon\"></span>'; 
  html += '<span class=\"text\">' + info.value + '</span>'; 
  html += '</div>'; 
  $(info.cell).html(html); 
}"
When defining renderers in risksheet.json, escape double quotes with backslashes: \". For complex renderers with extensive HTML, consider storing the function in an external JavaScript file and referencing it via script injection.

Performance Optimization

Cache expensive lookups:
"optimizedRenderer": "function(info) { 
  if(!window.rendererCache) window.rendererCache = {}; 
  var key = info.item.id + '_' + info.value; 
  if(!window.rendererCache[key]) { 
    window.rendererCache[key] = someExpensiveCalculation(info.value); 
  } 
  $(info.cell).text(window.rendererCache[key]); 
}"

Renderer vs Formula vs Decorator

FeatureCell RendererFormulaCell Decorator
PurposeDisplay formattingCalculate valuesApply CSS classes
ExecutionEvery renderOn data changeEvery render
PerformanceModerate impactLow impactLow impact
Modifies DataNoYesNo
Best ForCustom HTML/iconsDerived valuesConditional styling
Custom renderers do not execute during comparison/baseline mode. If your renderer provides critical visual information, users may lose context when comparing revisions. Consider using conditional formatting with CSS classes for styling that persists in comparison mode.

Verification

  1. Save your configuration changes via the Configuration Editor
  2. Reload the RISKSHEET page
  3. You should now see your custom rendering applied to the configured column
  4. Modify work item field values that trigger renderer conditions
  5. Verify the cell appearance updates according to your renderer logic
  6. Test rendering performance with large datasets (100+ rows)
  7. Check browser console for JavaScript errors

Troubleshooting

Renderer doesn’t execute: Verify the cellRenderer value exactly matches the key in cellDecorators. Check browser console for JavaScript syntax errors. jQuery not working: Ensure you’re wrapping DOM elements with $(info.cell). The raw info.cell is a DOM element, not a jQuery object. Rendering flickers: Renderers execute frequently. Avoid DOM manipulation that causes reflow. Use CSS class toggles instead of direct style manipulation when possible. Changes don’t persist on save: Renderers only affect display, not data. To modify actual work item values, use formulas instead.

See Also

Support TicketsSource Code
  • CellPreviewFormatter.ts
  • WorkItemBasedReview.java
  • risksheet.json
  • RisksheetProjectProperties.java
  • AppConfig.ts