Spreadsheet tools
Merged cells, a fill handle, a status bar with totals, pinned rows and Ctrl+F find.
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 });
// Sorted by country so identical countries sit together and merge into one tall cell.
const data = makeRows(400).sort((a, b) => a.country.localeCompare(b.country) || a.company.localeCompare(b.company));
const money = { type: 'number', format: '#,##0', width: 110, editable: true } as const;
const columns: ColumnDef[] = [
{ field: 'country', header: h('Country', '국가'), width: 140, pinned: 'left', merge: true },
{ field: 'company', header: h('Company', '회사'), width: 140, merge: true },
{ field: 'name', header: h('Name', '이름'), width: 160, editable: true },
{ field: 'q1', header: h('Q1 revenue', '1분기 매출'), ...money, wrapHeaderText: true },
{ field: 'q2', header: h('Q2 revenue', '2분기 매출'), ...money, wrapHeaderText: true },
{ field: 'q3', header: h('Q3 revenue', '3분기 매출'), ...money, wrapHeaderText: true },
{ field: 'q4', header: h('Q4 revenue', '4분기 매출'), ...money, wrapHeaderText: true },
{ field: 'joined', header: h('Joined', '가입일'), type: 'date', width: 120, editable: true },
];
const grid = createGrid(ctx.host, {
columns,
data,
locale: lang,
theme: 'erp',
statusBar: true, // counts and totals of the selected cells
fillHandle: true, // drag the blue corner to fill
pinnedTopRows: [{ country: h('Target', '목표'), name: '—', q1: 50000, q2: 55000, q3: 60000, q4: 65000 }],
});
grid.on('cellValueChanged', e => ctx.log(`cellValueChanged → ${e.colId}: ${String(e.oldValue)} → ${String(e.newValue)}`));
text(ctx, h('Drag across Q1–Q4 cells to see totals below. Pull the blue corner down to fill. Ctrl+F finds.',
'1~4분기 셀을 드래그하면 아래에 합계가 나옵니다. 파란 모서리를 끌어내려 채워 보세요. Ctrl+F로 찾기.'));
separator(ctx);
button(ctx, h('Find "Granite"', '"Granite" 찾기'), () => ctx.log(`find → ${grid.find('Granite')} matches`));
button(ctx, h('Next match', '다음 찾기'), () => grid.findNext());
button(ctx, h('Clear find', '찾기 지우기'), () => grid.clearFind());
button(ctx, h('Fill Q1 of the first 10 rows with a series', '첫 10행 1분기를 연속값으로 채우기'), () => {
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;
}