Реализация 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="ru"
/>
</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 дней.







