Skip to main content

Overview

Cell Renderers allow you to customize how cell values are displayed in the grid without entering edit mode. Use cell renderers to:
  • Format and display complex data structures
  • Add icons, images, and rich HTML content
  • Create interactive elements like buttons and links
  • Display progress bars, charts, and custom visualizations
  • Implement conditional formatting and styling
Cell renderers are read-only components. For editable cells, use Cell Editors instead.

ICellRendererParams Interface

The grid provides cell renderers with a params object containing all necessary information:
interface ICellRendererParams<TData = any, TValue = any, TContext = any> 
  extends AgGridCommon<TData, TContext> {
  /** Value to be rendered */
  value: TValue | null | undefined;
  
  /** Formatted value (if valueFormatter is defined) */
  valueFormatted: string | null | undefined;
  
  /** True if this is a full width row */
  fullWidth?: boolean;
  
  /** Pinned state of the cell ('left', 'right', or null) */
  pinned?: 'left' | 'right' | null;
  
  /** The row's data (can be undefined for row grouping) */
  data: TData | undefined;
  
  /** The row node */
  node: IRowNode<TData>;
  
  /** The cell's column definition */
  colDef?: ColDef<TData, TValue>;
  
  /** The cell's column */
  column?: Column<TValue>;
  
  /** The grid's cell DOM element */
  eGridCell: HTMLElement;
  
  /** Parent DOM element for the cell renderer */
  eParentOfValue: HTMLElement;
  
  /** Get the most recent value */
  getValue?: () => TValue | null | undefined;
  
  /** Set the cell value */
  setValue?: (value: TValue | null | undefined) => void;
  
  /** Format a value using the column's formatter */
  formatValue?: (value: TValue | null | undefined) => string;
  
  /** Refresh the cell */
  refreshCell?: () => void;
  
  /** Register a row dragger element */
  registerRowDragger: (
    rowDraggerElement: HTMLElement,
    dragStartPixels?: number,
    value?: string,
    suppressVisibilityChange?: boolean
  ) => void;
  
  /** Set a tooltip for this component */
  setTooltip: (value: string, shouldDisplayTooltip?: () => boolean) => void;
}

ICellRenderer Interface

Implement this interface to create a custom cell renderer:
interface ICellRenderer<TData = any> {
  /**
   * Called when the cell is refreshed.
   * Return true if successful, false to destroy and recreate.
   */
  refresh(params: ICellRendererParams<TData>): boolean;
}

Complete Component Interface

interface ICellRendererComp<TData = any> 
  extends IComponent<ICellRendererParams<TData>>, 
          ICellRenderer<TData> {
  /** Initialize the component */
  init(params: ICellRendererParams<TData>): void;
  
  /** Return the DOM element */
  getGui(): HTMLElement;
  
  /** Refresh the component */
  refresh(params: ICellRendererParams<TData>): boolean;
  
  /** Called after GUI is attached */
  afterGuiAttached?(): void;
  
  /** Clean up resources */
  destroy?(): void;
}

Basic Examples

class SimpleCellRenderer {
  init(params) {
    this.eGui = document.createElement('div');
    this.eGui.innerHTML = `
      <strong style="color: #04dcfc;">
        ${params.value || ''}
      </strong>
    `;
  }

  getGui() {
    return this.eGui;
  }

  refresh(params) {
    this.eGui.querySelector('strong').textContent = params.value || '';
    return true;
  }

  destroy() {
    // Cleanup if needed
  }
}

// Column definition
const columnDefs = [
  {
    field: 'athlete',
    cellRenderer: SimpleCellRenderer
  }
];

Advanced Examples

Button Renderer with Event Handling

class ButtonCellRenderer {
  init(params) {
    this.params = params;
    this.eGui = document.createElement('div');
    this.eButton = document.createElement('button');
    this.eButton.className = 'btn-simple';
    this.eButton.textContent = 'Click Me';
    
    this.eventListener = () => {
      alert(`Clicked: ${params.data.athlete}`);
    };
    this.eButton.addEventListener('click', this.eventListener);
    
    this.eGui.appendChild(this.eButton);
  }

  getGui() {
    return this.eGui;
  }

  refresh() {
    return false; // Don't refresh, recreate instead
  }

  destroy() {
    if (this.eventListener) {
      this.eButton.removeEventListener('click', this.eventListener);
    }
  }
}

Image Renderer with Fallback

class ImageCellRenderer {
  init(params) {
    this.eGui = document.createElement('div');
    this.eGui.className = 'image-cell';
    
    const img = document.createElement('img');
    img.src = params.value || 'default-avatar.png';
    img.alt = params.data.name;
    img.style.width = '32px';
    img.style.height = '32px';
    img.style.borderRadius = '50%';
    
    img.onerror = () => {
      img.src = 'default-avatar.png';
    };
    
    this.eGui.appendChild(img);
  }

  getGui() {
    return this.eGui;
  }

  refresh(params) {
    const img = this.eGui.querySelector('img');
    img.src = params.value || 'default-avatar.png';
    img.alt = params.data.name;
    return true;
  }
}

Status Badge Renderer

class StatusCellRenderer {
  init(params) {
    this.eGui = document.createElement('span');
    this.refresh(params);
  }

  getGui() {
    return this.eGui;
  }

  refresh(params) {
    const status = params.value?.toLowerCase();
    const statusConfig = {
      active: { color: '#10b981', label: 'Active' },
      pending: { color: '#f59e0b', label: 'Pending' },
      inactive: { color: '#ef4444', label: 'Inactive' }
    };

    const config = statusConfig[status] || statusConfig.inactive;
    
    this.eGui.innerHTML = `
      <span style="
        background-color: ${config.color}20;
        color: ${config.color};
        padding: 4px 12px;
        border-radius: 12px;
        font-size: 12px;
        font-weight: 600;
      ">
        ${config.label}
      </span>
    `;
    
    return true;
  }
}

Cell Renderer Functions

For simple cases, you can use a function instead of a class:
const columnDefs = [
  {
    field: 'price',
    cellRenderer: (params) => {
      if (params.value == null) return '';
      return `$${params.value.toFixed(2)}`;
    }
  },
  {
    field: 'status',
    cellRenderer: (params) => {
      const icon = params.value === 'active' ? '✓' : '✗';
      return `<span>${icon} ${params.value}</span>`;
    }
  }
];
Cell renderer functions cannot implement the refresh() method. The cell will be recreated on every data change, which may impact performance.

Built-in Cell Renderers

AG Grid provides several built-in cell renderers:

Checkbox Cell Renderer

const columnDefs = [
  {
    field: 'selected',
    cellRenderer: 'agCheckboxCellRenderer',
    cellRendererParams: {
      disabled: false
    }
  }
];

Group Cell Renderer

const columnDefs = [
  {
    field: 'country',
    cellRenderer: 'agGroupCellRenderer',
    cellRendererParams: {
      innerRenderer: (params) => params.value,
      suppressCount: false
    }
  }
];

Suppressing Mouse Event Handling

Prevent the grid from handling mouse events in your cell renderer:
interface EventCellRendererParams<TData = any, TValue = any, TContext = any> {
  suppressMouseEventHandling?: (
    params: SuppressMouseEventHandlingParams<TData, TValue, TContext>
  ) => boolean;
}

interface SuppressMouseEventHandlingParams<TData = any, TValue = any, TContext = any> {
  node: IRowNode<TData>;
  column?: Column<TValue>;
  event: MouseEvent;
}
Example usage:
const columnDefs = [
  {
    field: 'action',
    cellRenderer: ButtonCellRenderer,
    suppressMouseEventHandling: (params) => {
      // Prevent grid from handling clicks on buttons
      return params.event.target.tagName === 'BUTTON';
    }
  }
];

Row Dragging

Register elements as row drag handles:
class DragHandleCellRenderer {
  init(params) {
    this.eGui = document.createElement('div');
    this.eGui.innerHTML = `
      <div class="drag-handle">⋮⋮</div>
      <span>${params.value}</span>
    `;
    
    const dragHandle = this.eGui.querySelector('.drag-handle');
    params.registerRowDragger(dragHandle);
  }

  getGui() {
    return this.eGui;
  }

  refresh() {
    return false;
  }
}

Tooltips

Set custom tooltips from your cell renderer:
class TooltipCellRenderer {
  init(params) {
    this.eGui = document.createElement('div');
    this.eGui.textContent = params.value;
    
    // Set tooltip
    params.setTooltip(
      `Full value: ${params.value}`,
      () => params.value?.length > 20 // Only show if value is long
    );
  }

  getGui() {
    return this.eGui;
  }

  refresh() {
    return true;
  }
}

Best Practices

Always try to implement refresh() to update your component instead of recreating it. Return true if successful, false to recreate:
refresh(params) {
  // Update existing DOM instead of recreating
  this.eGui.querySelector('.value').textContent = params.value;
  return true; // Successfully refreshed
}
Always remove event listeners in the destroy() method:
destroy() {
  if (this.clickListener) {
    this.eButton.removeEventListener('click', this.clickListener);
  }
}
The valueFormatted parameter contains the formatted value if a valueFormatter is defined:
init(params) {
  const displayValue = params.valueFormatted ?? params.value;
  this.eGui.textContent = displayValue;
}
Always check for null/undefined values:
init(params) {
  const value = params.value ?? 'N/A';
  this.eGui.textContent = value;
}

TypeScript Support

Use generics for type-safe cell renderers:
interface Athlete {
  name: string;
  country: string;
  sport: string;
}

class TypedCellRenderer implements ICellRendererComp<Athlete> {
  private eGui: HTMLElement;
  private params: ICellRendererParams<Athlete>;

  init(params: ICellRendererParams<Athlete>): void {
    this.params = params;
    this.eGui = document.createElement('div');
    
    // TypeScript knows params.data is Athlete
    this.eGui.textContent = `${params.data.name} - ${params.data.country}`;
  }

  getGui(): HTMLElement {
    return this.eGui;
  }

  refresh(params: ICellRendererParams<Athlete>): boolean {
    this.params = params;
    this.eGui.textContent = `${params.data.name} - ${params.data.country}`;
    return true;
  }
}

Next Steps

Cell Editors

Learn about custom cell editors for data input

Filters

Create custom filter components