name: handsontable-renderer-dev path: handsontable/src/renderers/** description: Use when creating or modifying a Handsontable cell renderer function that controls how cell content is displayed in the DOM - pure functions that take cell data and modify TD element
Handsontable Renderer Development
Function signature
Renderers are pure functions with no class or state:
function myRenderer(hotInstance, TD, row, col, prop, value, cellProperties) {
baseRenderer.apply(this, arguments);
// Modify TD element here
}
Always call baseRenderer first. It applies common properties: readonly CSS class, invalid CSS class, ARIA attributes, and other standard cell setup.
Key rules
- Stateless and read-only. Renderers only modify the TD element's DOM content and attributes. Never store state, attach event listeners, or mutate data.
- Use
fastInnerText(TD, value)fromsrc/helpers/dom/element.tsfor setting cell text content. It is XSS-safe and cross-browser optimized. - Never use
innerHTMLwithout sanitization. All user-provided content must be escaped to prevent XSS. - No event listeners. If you need interactivity, that belongs in an editor or a plugin, not a renderer.
- ARIA attributes.
baseRendererhandles standard ARIA. If your renderer changes the cell's role or state, update ARIA attributes accordingly.
File structure
src/renderers/{rendererName}/
{rendererName}.ts # Renderer function
index.ts # Re-exports
Registry: src/renderers/registry.ts.
Registration
import { registerRenderer } from '../../renderers/registry';
registerRenderer('myRenderer', myRenderer);
Reference implementations
src/renderers/baseRenderer/baseRenderer.ts- Must be called by every renderer.src/renderers/textRenderer/textRenderer.ts- Simplest renderer, good starting template.src/renderers/htmlRenderer/htmlRenderer.ts- Renders raw HTML (use with caution).src/renderers/numericRenderer/numericRenderer.ts- Formatting with numeral.js.
Performance
Renderers are called for every cell in the viewport on every render cycle (both fast and slow renders). They must be highly optimized:
- Keep logic minimal - avoid DOM-heavy operations
- Never read layout properties inside a renderer (
getBoundingClientRect,offsetWidth) - causes layout thrashing - Avoid object allocations and complex string concatenations in the hot path
- The simpler the renderer, the better
Common mistakes
- Forgetting to call
baseRendererfirst, which skips readonly/invalid CSS and ARIA setup. - Adding event listeners in a renderer (use editors or plugins instead).
- Using
innerHTMLwith unsanitized user input. - Mutating
cellPropertiesor source data inside a renderer. - Not handling
nullorundefinedvalues gracefully.