FreeGridv1.15.1한국어

Fill handle

Drag the corner of a selection to fill editable cells: numbers and dates continue their step and numbered text counts up, in one undo step.

Live demoFill handle

Drag the corner of a selection to continue numbers, dates and numbered text.

Code for this demo
import { createGrid, type ColumnDef } from '@freegridjs/core';
import { makeRows } from '../data';
import { button, separator, text, tr, type DemoContext } from '../ui';

export default function mount(ctx: DemoContext) {
  const { lang } = ctx;
  const h = (en: string, ko: string) => tr(lang, { en, ko });
  const money = { type: 'number', format: '#,##0', width: 110, editable: true } as const;
  const columns: ColumnDef[] = [
    { field: 'name', header: h('Name', '이름'), width: 160, editable: true },
    { field: 'q1', header: h('Q1 revenue', '1분기 매출'), ...money },
    { field: 'q2', header: h('Q2 revenue', '2분기 매출'), ...money },
    { field: 'q3', header: h('Q3 revenue', '3분기 매출'), ...money },
    { field: 'q4', header: h('Q4 revenue', '4분기 매출'), ...money },
    { field: 'joined', header: h('Joined', '가입일'), type: 'date', width: 120, editable: true },
    { field: 'country', header: h('Country (read-only)', '국가 (읽기 전용)'), width: 150 },
  ];
  const grid = createGrid(ctx.host, {
    columns,
    data: makeRows(400),
    locale: lang,
    theme: 'excel',
    fillHandle: true, // drag the square at the corner of the selection
  });
  grid.on('cellValueChanged', e => ctx.log(`cellValueChanged → ${e.colId}: ${String(e.oldValue)} → ${String(e.newValue)}`));

  text(ctx, h('Select one or two cells and pull the small square at the corner down or across. Read-only cells are left alone.',
    '셀 한두 개를 고른 뒤 모서리의 작은 사각형을 아래나 옆으로 끌어 보세요. 읽기 전용 셀은 그대로 둡니다.'));
  separator(ctx);
  button(ctx, h('Fill Q1 of the first 10 rows with 1,000, 2,000 …', '첫 10행 1분기를 1,000, 2,000 …으로 채우기'), () => {
    grid.setRange({ start: { rowIndex: 0, colId: 'q1' }, end: { rowIndex: 0, colId: 'q1' } });
    grid.pasteText('1000\n2000');
    grid.setRange({ start: { rowIndex: 0, colId: 'q1' }, end: { rowIndex: 1, colId: 'q1' } });
    grid.fillRange({ start: { rowIndex: 0, colId: 'q1' }, end: { rowIndex: 9, colId: 'q1' } });
  });
  button(ctx, h('Undo', '실행 취소'), () => grid.undo());
  return grid;
}

Select one or more cells and a small square appears at the corner of the selection. Drag it down, up or sideways and the cells you pass are filled, the way a spreadsheet does it: numbers and dates continue their step (1, 2 → 3, 4, 5; Jan 1, Jan 8 → Jan 15), text that ends in a number counts up ("item 7" → "item 8"), and anything else repeats. Only editable cells change; ids and computed columns are left alone.

A fill is one undo step and fires cellValueChanged for every cell, like an edit, so the change log and your save logic see it. Values that break a validation rule are skipped. fillRange() does the same from code, and fillHandle: false hides the square.

createGrid(el, {
  columns: [
    { field: 'month', editable: true },                  // "Jan", "Feb" → copies; "item 7" → "item 8"
    { field: 'q1', type: 'number', editable: true },     // 1, 2 → 3, 4, 5 …
    { field: 'due', type: 'date', editable: true },      // dates keep their step
  ],
  data,
  fillHandle: true,   // default; false hides the square at the corner of the selection
});

// the same from code: from the selected cells into a larger range (one undo step)
grid.setRange({ start: { rowIndex: 0, colId: 'q1' }, end: { rowIndex: 1, colId: 'q1' } });
grid.fillRange({ start: { rowIndex: 0, colId: 'q1' }, end: { rowIndex: 9, colId: 'q1' } });

The fill handle works on cell ranges.

Options and methods

NameTypeDescription
fillHandlebooleanThe small square at the corner of the selection (default true).
fillRange(target)voidFill from the selected cells (or the focused cell) into target, which must contain them; one undo step.