Handsontable example

by Blake Gilchrist

HTML

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/handsontable.full.min.js"></script>
<link type="text/css" rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/styles/handsontable.min.css" /> 
<link type="text/css" rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/styles/ht-theme-main.css" /> 
<script src="https://handsontable.com/docs/scripts/fixer.js"></script>

<div id="example2" class="hot"></div>

Babel + JSX

import Handsontable from 'handsontable/base';
import { registerAllModules } from 'handsontable/registry';
import 'handsontable/styles/handsontable.css';
import 'handsontable/styles/ht-theme-main.css';

registerAllModules();


const tableColumns = [
  { position: 'A', label: 'Status', parentField: '' },
  { position: 'B', label: 'Buying Audience', parentField: 'Dimension' },
  { position: 'C', label: 'Channel *', parentField: 'Dimension' },
  { position: 'D', label: 'Objective *', parentField: 'Dimension' },
  { position: 'E', label: 'Product *', parentField: 'Dimension' },
  { position: 'F', label: 'Vendor *', parentField: 'Flights' },
  { position: 'G', label: 'Start Date *', parentField: 'Flights' },
  { position: 'H', label: 'End Date *', parentField: 'Costs & Fees' },
  { position: 'I', label: 'Exchange Rate', parentField: 'Costs & Fees' },
  { position: 'J', label: 'Ratecard Cost *', parentField: 'Comments' },
];

const data = Array.from({ length: 8 }, (_, r) =>
  Array.from({ length: tableColumns.length }, (_, c) => `${tableColumns[c].position}${r + 1}`)
);

const buildParentHeaders = (cols) => {
  const headers = [];
  let currentLabel = null;
  let currentSpan = 0;

  const pushCurrent = () => {
    if (currentSpan > 0) {
      headers.push(currentSpan > 1 ? { label: currentLabel, colspan: currentSpan } : currentLabel);
    }
  };

  cols.forEach((col) => {
    const label = col.parentField ?? '';
    if (!label) {
      pushCurrent();
      currentLabel = null;
      currentSpan = 0;
      headers.push('');
      return;
    }
    if (label === currentLabel) {
      currentSpan += 1;
    } else {
      pushCurrent();
      currentLabel = label;
      currentSpan = 1;
    }
  });

  pushCurrent();
  return headers;
};

const cloneNestedHeaders = (headers) =>
  headers.map((row) =>
    row.map((cell) => (cell && typeof cell === 'object' ? { ...cell } : cell))
  );

const getPhysicalOrder =...