CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-data-grid

Excel-like grid component built with React, with editors, keyboard navigation, copy & paste, and the like

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

formatters.mddocs/

Formatters and Display

Cell formatting functionality providing built-in formatters and infrastructure for custom cell display components.

Capabilities

Built-in Formatters

Pre-built formatter components for common cell display scenarios.

const formatters = {
  /** Basic cell formatter for simple value display */
  SimpleCellFormatter: React.ComponentType<FormatterProps>;
  /** Checkbox formatter for select-all functionality in headers */
  SelectAll: React.ComponentType<FormatterProps>;
};

interface FormatterProps {
  /** Cell value to format and display */
  value: any;
  /** Complete row data object */
  row: any;
  /** Column definition */
  column: Column;
  /** Row index */
  rowIdx: number;
  /** Whether the cell is currently selected */
  isSelected?: boolean;
  /** Whether row selection is enabled */
  isRowSelected?: boolean;
  /** Additional properties passed from column definition */
  [key: string]: any;
}

SimpleCellFormatter

Basic formatter that displays cell values as text with null/undefined handling.

/**
 * Simple cell formatter for displaying basic text values
 * Handles null/undefined values gracefully
 * Supports title attribute for hover tooltips
 */
const SimpleCellFormatter: React.ComponentType<FormatterProps>;

Usage Example:

import ReactDataGrid, { formatters } from 'react-data-grid';

const columns = [
  { key: 'id', name: 'ID' },
  { 
    key: 'name', 
    name: 'Name',
    formatter: <formatters.SimpleCellFormatter />
  },
  { 
    key: 'description', 
    name: 'Description',
    formatter: <formatters.SimpleCellFormatter />
  }
];

<ReactDataGrid
  columns={columns}
  rowGetter={i => rows[i]}
  rowsCount={rows.length}
  minHeight={400}
/>

SelectAll Formatter

Specialized formatter for rendering select-all checkboxes in header cells.

/**
 * Select-all checkbox formatter for header cells
 * Provides master checkbox to select/deselect all rows
 * Works with rowSelection configuration
 */
const SelectAll: React.ComponentType<FormatterProps>;

Usage Example:

import ReactDataGrid, { formatters } from 'react-data-grid';

const columns = [
  { 
    key: 'select',
    name: '',
    formatter: <formatters.SelectAll />,
    width: 60,
    resizable: false,
    sortable: false,
    frozen: true
  },
  { key: 'id', name: 'ID' },
  { key: 'name', name: 'Name' }
];

const rowSelection = {
  showCheckbox: true,
  enableShiftSelect: true,
  onRowsSelected: (rows) => console.log('Selected:', rows),
  onRowsDeselected: (rows) => console.log('Deselected:', rows),
  selectBy: {
    indexes: selectedIndexes
  }
};

<ReactDataGrid
  columns={columns}
  rowGetter={i => rows[i]}
  rowsCount={rows.length}
  minHeight={400}
  rowSelection={rowSelection}
/>

Custom Formatter Creation

Creating custom formatters for specialized cell display requirements.

/**
 * Interface for custom formatter components
 * Receives cell data and returns JSX for display
 */
interface CustomFormatter extends React.Component<FormatterProps> {
  render(): JSX.Element;
}

Custom Formatter Examples:

import React from 'react';

// Currency formatter
const CurrencyFormatter = ({ value }) => {
  const formattedValue = new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency: 'USD'
  }).format(value || 0);
  
  return (
    <div style={{ textAlign: 'right', fontWeight: 'bold' }}>
      {formattedValue}
    </div>
  );
};

// Status badge formatter
const StatusFormatter = ({ value }) => {
  const getStatusColor = (status) => {
    switch (status) {
      case 'active': return '#28a745';
      case 'inactive': return '#dc3545';
      case 'pending': return '#ffc107';
      default: return '#6c757d';
    }
  };
  
  return (
    <span
      style={{
        padding: '4px 8px',
        borderRadius: '4px',
        backgroundColor: getStatusColor(value),
        color: 'white',
        fontSize: '12px',
        fontWeight: 'bold'
      }}
    >
      {value || 'unknown'}
    </span>
  );
};

// Progress bar formatter
const ProgressFormatter = ({ value }) => {
  const percentage = Math.max(0, Math.min(100, value || 0));
  
  return (
    <div style={{ width: '100%', backgroundColor: '#e9ecef', borderRadius: '4px' }}>
      <div
        style={{
          width: `${percentage}%`,
          height: '20px',
          backgroundColor: '#007bff',
          borderRadius: '4px',
          textAlign: 'center',
          lineHeight: '20px',
          color: 'white',
          fontSize: '12px'
        }}
      >
        {percentage}%
      </div>
    </div>
  );
};

// Link formatter
const LinkFormatter = ({ value, row }) => {
  return (
    <a 
      href={value} 
      target="_blank" 
      rel="noopener noreferrer"
      style={{ color: '#007bff', textDecoration: 'underline' }}
    >
      {row.linkText || 'View'}
    </a>
  );
};

// Image formatter
const ImageFormatter = ({ value }) => {
  return value ? (
    <img 
      src={value} 
      alt="Preview" 
      style={{ 
        width: '40px', 
        height: '40px', 
        objectFit: 'cover',
        borderRadius: '4px'
      }} 
    />
  ) : (
    <div style={{ 
      width: '40px', 
      height: '40px', 
      backgroundColor: '#f8f9fa',
      border: '1px dashed #dee2e6',
      borderRadius: '4px'
    }} />
  );
};

// Usage in columns
const columns = [
  { key: 'id', name: 'ID' },
  { key: 'name', name: 'Name' },
  { 
    key: 'price', 
    name: 'Price',
    formatter: <CurrencyFormatter />
  },
  { 
    key: 'status', 
    name: 'Status',
    formatter: <StatusFormatter />
  },
  { 
    key: 'progress', 
    name: 'Progress',
    formatter: <ProgressFormatter />
  },
  { 
    key: 'website', 
    name: 'Website',
    formatter: <LinkFormatter />
  },
  { 
    key: 'avatar', 
    name: 'Avatar',
    formatter: <ImageFormatter />,
    width: 80
  }
];

Conditional Formatting

Using formatters with conditional logic based on cell values or row data.

// Conditional cell styling formatter
const ConditionalFormatter = ({ value, row, column }) => {
  const getStyle = () => {
    if (column.key === 'amount' && value < 0) {
      return { color: 'red', fontWeight: 'bold' };
    }
    if (column.key === 'status' && row.priority === 'high') {
      return { backgroundColor: '#fff3cd', padding: '4px' };
    }
    return {};
  };
  
  return (
    <div style={getStyle()}>
      {value}
    </div>
  );
};

// Multi-value formatter
const TagsFormatter = ({ value }) => {
  const tags = Array.isArray(value) ? value : [];
  
  return (
    <div style={{ display: 'flex', gap: '4px', flexWrap: 'wrap' }}>
      {tags.map((tag, index) => (
        <span
          key={index}
          style={{
            padding: '2px 6px',
            backgroundColor: '#e9ecef',
            borderRadius: '12px',
            fontSize: '11px',
            color: '#495057'
          }}
        >
          {tag}
        </span>
      ))}
    </div>
  );
};

// Date formatter
const DateFormatter = ({ value }) => {
  if (!value) return null;
  
  const date = new Date(value);
  const formattedDate = date.toLocaleDateString('en-US', {
    year: 'numeric',
    month: 'short',
    day: 'numeric'
  });
  
  return (
    <div title={date.toISOString()}>
      {formattedDate}
    </div>
  );
};

Formatter Configuration

Column-level configuration for cell formatting and display.

interface FormattedColumn extends Column {
  /** Custom formatter component for cell display */
  formatter?: React.ComponentType<FormatterProps>;
  /** Additional properties passed to formatter */
  [key: string]: any;
}

Advanced Formatting Patterns

Complex formatting scenarios with interactive elements and custom styling.

// Interactive formatter with buttons
const ActionFormatter = ({ value, row, rowIdx }) => {
  const handleEdit = () => {
    console.log('Edit row:', rowIdx, row);
  };
  
  const handleDelete = () => {
    console.log('Delete row:', rowIdx, row);
  };
  
  return (
    <div style={{ display: 'flex', gap: '4px' }}>
      <button
        onClick={handleEdit}
        style={{
          padding: '2px 8px',
          fontSize: '12px',
          backgroundColor: '#007bff',
          color: 'white',
          border: 'none',
          borderRadius: '4px',
          cursor: 'pointer'
        }}
      >
        Edit
      </button>
      <button
        onClick={handleDelete}
        style={{
          padding: '2px 8px',
          fontSize: '12px',
          backgroundColor: '#dc3545',
          color: 'white',
          border: 'none',
          borderRadius: '4px',
          cursor: 'pointer'
        }}
      >
        Delete
      </button>
    </div>
  );
};

// Rich content formatter
const RichContentFormatter = ({ value, row }) => {
  return (
    <div style={{ padding: '4px' }}>
      <div style={{ fontWeight: 'bold', fontSize: '14px' }}>
        {row.title}
      </div>
      <div style={{ fontSize: '12px', color: '#6c757d' }}>
        {row.subtitle}
      </div>
      <div style={{ fontSize: '11px', marginTop: '2px' }}>
        {value}
      </div>
    </div>
  );
};

// Sparkline formatter (requires chart library)
const SparklineFormatter = ({ value }) => {
  const data = Array.isArray(value) ? value : [];
  
  return (
    <div style={{ width: '100px', height: '30px' }}>
      {/* Would integrate with chart library like Chart.js or D3 */}
      <svg width="100" height="30">
        {data.map((point, index) => (
          <circle
            key={index}
            cx={index * (100 / data.length)}
            cy={30 - (point * 30)}
            r="2"
            fill="#007bff"
          />
        ))}
      </svg>
    </div>
  );
};

Performance Considerations

  • Formatters are called for every visible cell during rendering
  • Keep formatter logic lightweight to maintain grid performance
  • Use React.memo for complex formatters to prevent unnecessary re-renders
  • Avoid heavy computations or API calls within formatters
import React, { memo } from 'react';

// Optimized formatter with memoization
const OptimizedFormatter = memo(({ value, row }) => {
  const expensiveCalculation = useMemo(() => {
    return complexCalculation(value);
  }, [value]);
  
  return (
    <div>
      {expensiveCalculation}
    </div>
  );
});

Install with Tessl CLI

npx tessl i tessl/npm-react-data-grid@6.1.1

docs

components.md

core-grid.md

editors.md

formatters.md

index.md

selection.md

utilities.md

tile.json