Реалізація Spreadsheet (таблиця як в Excel) на сайті
Електронна таблиця у браузері — один з найбільш технічно складних UI-компонентів. Віртуалізація рядків та колонок, редагування ячейок, формули, мерж ячейок, копіювання через буфер обміну, виділення діапазонів — кожна з цих функцій потребує окремої роботи. Реалізовувати з нуля на <div> — багато місяців. Використовувати готову бібліотеку — питання вибору правильної.
Бібліотеки
Handsontable — де-факто стандарт для комерційних проектів. Ліцензія: безплатно лише для некомерційних. Для комерції — платна (від $149/розробник). Зате повний Excel-like досвід.
HyperFormula — рушій формул від команди Handsontable, MIT-ліцензія. Можна використовувати як обчислювальне ядро для будь-якого UI.
@fortune-sheet/react — повноцінний open-source spreadsheet, MIT. Активна розробка, хороша альтернатива Handsontable.
TanStack Table + редаговані ячейки — якщо потрібна таблиця з інлайн-редаганням, але не повний spreadsheet. Набагато простіше.
Handsontable: швидкий старт
npm install handsontable @handsontable/react
import { HotTable, HotTableClass } from '@handsontable/react'
import { registerAllModules } from 'handsontable/registry'
import 'handsontable/dist/handsontable.full.min.css'
registerAllModules() // Реєструємо усі плагіни
interface SpreadsheetProps {
data: (string | number | null)[][]
onChange: (data: (string | number | null)[][]) => void
}
export function Spreadsheet({ data, onChange }: SpreadsheetProps) {
const hotRef = useRef<HotTableClass>(null)
const columns = [
{ data: 0, title: 'Продукт', type: 'text', width: 200 },
{ data: 1, title: 'Кол-во', type: 'numeric', numericFormat: { pattern: '0,0' } },
{ data: 2, title: 'Ціна', type: 'numeric', numericFormat: { pattern: '0,0.00 ₴' } },
{
data: 3,
title: 'Сума',
type: 'numeric',
numericFormat: { pattern: '0,0.00 ₴' },
readOnly: true,
},
{
data: 4,
title: 'Статус',
type: 'dropdown',
source: ['В наявності', 'Під замовлення', 'Знято з продажу'],
},
]
return (
<HotTable
ref={hotRef}
data={data}
columns={columns}
rowHeaders={true}
colHeaders={true}
contextMenu={true} // Правий клік: вставити/видалити рядок
copyPaste={true} // Ctrl+C/V як в Excel
manualColumnResize={true}
manualRowResize={true}
manualColumnMove={true}
filters={true} // Фільтрація за колонкою
dropdownMenu={true} // Меню колонки з фільтрами
multiColumnSorting={true}
undo={true} // Ctrl+Z
mergeCells={true}
autoRowSize={false}
autoColumnSize={false}
height="500px"
width="100%"
licenseKey="non-commercial-and-evaluation"
afterChange={(changes) => {
if (!changes) return
onChange(hotRef.current!.hotInstance!.getData())
}}
/>
)
}
Формули з HyperFormula
npm install hyperformula
import { HyperFormula } from 'hyperformula'
import { HotTable } from '@handsontable/react'
function SpreadsheetWithFormulas() {
const hfInstance = HyperFormula.buildEmpty({
licenseKey: 'gpl-v3',
})
return (
<HotTable
formulas={{
engine: hfInstance,
sheetName: 'Sheet1',
}}
data={[
['Продукт', 'Кол-во', 'Ціна', 'Сума'],
['Товар А', 10, 150, '=B2*C2'],
['Товар Б', 5, 300, '=B3*C3'],
['', '', 'Всього:', '=SUM(D2:D3)'],
]}
// ...
/>
)
}
HyperFormula підтримує 386 функцій, включаючи VLOOKUP, SUMIF, DATE-функції, масивні формули.
Fortune-Sheet: open-source альтернатива
npm install @fortune-sheet/react
import { Workbook } from '@fortune-sheet/react'
import '@fortune-sheet/react/dist/index.css'
function FortuneSpreadsheet() {
const [sheets, setSheets] = useState([
{
name: 'Sheet1',
celldata: [
{ r: 0, c: 0, v: { v: 'Товар', m: 'Товар', ct: { fa: 'General', t: 'g' } } },
{ r: 0, c: 1, v: { v: 'Ціна', m: 'Ціна', ct: { fa: 'General', t: 'g' } } },
{ r: 1, c: 0, v: { v: 'Кава', m: 'Кава' } },
{ r: 1, c: 1, v: { v: 250, m: '250', ct: { fa: '#,##0.00', t: 'n' } } },
],
row: 100,
column: 26,
},
])
return (
<div style={{ height: '600px' }}>
<Workbook
data={sheets}
onChange={setSheets}
showFormulaBar={true}
showToolbar={true}
lang="uk"
/>
</div>
)
}
Fortune-Sheet підтримує формули, умовне форматування, графіки, мерж ячейок, імпорт/експорт XLSX через SheetJS.
Експорт в Excel (XLSX)
npm install xlsx
import * as XLSX from 'xlsx'
function exportToExcel(hot: Handsontable) {
const data = hot.getData()
const headers = hot.getColHeader() as string[]
const ws = XLSX.utils.aoa_to_sheet([headers, ...data])
// Ширина колонок
ws['!cols'] = headers.map(() => ({ wch: 20 }))
const wb = XLSX.utils.book_new()
XLSX.utils.book_append_sheet(wb, ws, 'Дані')
XLSX.writeFile(wb, `export-${new Date().toISOString().slice(0,10)}.xlsx`)
}
Що робимо
Розбираємось з вимогами: потрібні ли формули, які типи даних, є ли обмеження за ліцензією (Handsontable платний для комерції). Підбираємо бібліотеку, налаштовуємо колонки та валідацію, підключаємо імпорт/експорт XLSX, інтегруємо з API для збереження даних.
Термін: базова редаговна таблиця без формул — 2–3 дні. Повноцінний spreadsheet з формулами та XLSX — 5–7 днів.







