Lattice Grid Buy a licence

demo D85

The fill handle: JavaScript Data Grid Demo

Dragging a corner to extend a series it recognises, with a pinned row-number column so a sort never loses count

fillHandle · rowNumbers

This grid extends a selection by dragging the small grip at its corner, filling the cells it crosses with a series it recognises. It brings the spreadsheet fill gesture to the grid, so a date or a pattern carries down a column with a drag. A pinned row-number column on the left counts the rows as they sit on screen, renumbering the moment you sort.

Building…
Loading a live grid…

The configuration

<link rel="stylesheet" href="https://cdn.latticegrid.dev/lattice-grid@1.103.2/lattice-grid.min.css">
<script src="https://cdn.latticegrid.dev/lattice-grid@1.103.2/lattice-grid.min.js"></script>

<div id="grid" style="height: 540px"></div>

<script>
  // rowNumbers is pinned ahead of the also-pinned Order column, and the
  // rows stay numbered 1..n after a click on any heading sorts the grid.
  const grid = LatticeGrid.createGrid(document.getElementById('grid'), {
    rowKey: 'id',
    selection: { mode: 'multiple', ranges: true, fillHandle: true },
    edit: true,
    rowNumbers: true,
    columns: [
      { field: 'id', title: 'Order', layout: { width: 120, pin: 'start' } },
      { field: 'reference', title: 'Reference', layout: { width: 130 } },
      { field: 'due', title: 'Due', type: 'date', layout: { width: 140 }, edit: true },
      { field: 'circuits', title: 'Circuits', type: 'number', layout: { width: 110 }, edit: true },
      { field: 'impact', title: 'Impact', type: 'number', layout: { width: 100 }, edit: true },
      { field: 'budget', title: 'Budget', type: 'number', layout: { width: 140 },
        format: { style: 'currency', currency: 'GBP' }, total: 'sum', edit: true },
    ],
    rows,  // work orders
  });

  // Left out of an export by default; opt in per call:
  // grid.export.csv({ rowNumbers: true })
</script>

Extending a series by dragging the fill handle

The fill handle is the small grip at the corner of a selected cell or range that, when dragged, extends the selection and populates the cells it crosses. A developer reaches for it wherever a spreadsheet-trained user expects to drag a date down a column and get the next few days, drag a “1” and a “2” and get “3, 4, 5”, or drag a single value across a row to repeat it. Lattice Grid exposes this through the fillHandle option: the grid inspects the source cells itself and works out whether the drag should repeat a constant, continue an arithmetic step, or advance a recognised date sequence. Because a JavaScript data grid handling this at scale cannot afford to recompute the whole visible range on every pointer move, the fill preview only touches the cells between the anchor and the current pointer position, and the write itself is a single batched update applied once the drag ends rather than one mutation per cell crossed. The result integrates with the grid’s existing range selection, so a filled range is immediately addressable for copy, further fill, or a subsequent formula reference, with no separate “fill mode” state to fall in or out of.

How do I let users drag-fill a series in a data grid, like Excel?

Enable fillHandle on the grid. It decides how a drag should extend the source cells on its own: as a repeated constant, an arithmetic sequence, or a date series. Lattice Grid renders the drag handle on the active selection’s corner, previews the affected cells as the pointer moves, and commits the filled values as one update when the drag is released.

A row-number column that always matches what’s on screen

rowNumbers: true adds a read-only column, pinned to the left, counting the rows in the order they are actually shown: after any sort, filter or grouping. Click a heading in this grid to sort it and the numbers in that left column stay a plain 1, 2, 3 run, because they count position rather than carrying a value stamped onto a row. Grouping is handled the same honest way: a group heading is not itself numbered, and the count continues across it rather than skipping or restarting, so the leaf rows underneath always add up. The column is for reading, not reporting; a CSV, Excel or clipboard export leaves it out by default; a call site that wants the numbers in the file passes { rowNumbers: true } to that export call, the same flag name whichever surface it is exporting to.