はじめに
「この在庫表、Excelで管理してるんだけど、Webシステムに移行できない?ただし操作感はExcelのままで」——業務システムの開発をしていると、一度は突きつけられる要望ではないでしょうか。
普通のHTMLテーブルとフォームで作り直すと、「セルをコピペできない」「矢印キーで移動できない」「使いにくくなった」と現場から不満が噴出します。Excelに慣れきったユーザーの期待値は、想像以上に高いのです。
そんなときに頼りになるのがHandsontableです。セルのコピー&ペースト、キーボード操作、数式、フィルタリングまで、Excelそっくりの編集体験をそのままWebアプリに埋め込めるデータグリッドライブラリです。この記事では、基本の導入から実践的な使い方までを解説します。
Handsontableとは
Handsontableは、スプレッドシートのようなUIと操作性を提供するJavaScript製のデータグリッドコンポーネントです。2012年から開発が続く老舗ライブラリで、2026年6月にはバージョン18.0.0がリリースされるなど、現在も活発にメンテナンスされています。
素のJavaScriptはもちろん、React・Angular・Vue 3向けの公式ラッパーが用意されているため、モダンなフロントエンド開発にもそのまま組み込めます。
主な特徴
- Excelライクな操作性 - セル編集、コピー&ペースト、フィルハンドルによるオートフィル、キーボードナビゲーションなど、スプレッドシートの操作感をほぼ再現しています
- 400以上の組み込み数式 - 数式エンジンのHyperFormulaと連携することで、
SUMやVLOOKUPといったExcel互換の数式をセルに書けます - 仮想化による高パフォーマンス - 行・列の仮想レンダリングにより、大量データでもスムーズにスクロールできます
- 豊富なデータ操作機能 - ソート、フィルタリング、データバリデーション、条件付き書式、セル結合、行列の固定・非表示などを標準サポートしています
- フレームワーク対応 - React、Angular、Vue 3の公式ラッパーが提供されています
ライセンスについて(重要)
導入前に必ず押さえておきたいのがライセンスです。Handsontableは商用利用には有料ライセンスが必要です。非商用利用や評価目的であれば、ライセンスキーに non-commercial-and-evaluation を指定することで無料で使えます。業務システムに組み込む場合はライセンス費用を見込んでおきましょう。
インストール
npmで一発です。素のJavaScriptで使う場合は本体のみをインストールします。
# npm
npm install handsontable
# yarn
yarn add handsontable
# pnpm
pnpm add handsontable
Reactで使う場合は公式ラッパーも一緒に入れます(React 18以上が必要です)。
npm install handsontable @handsontable/react-wrapper
基本的な使い方
まずは素のJavaScriptでの最小構成です。コンテナ要素を用意して、データを渡すだけで動きます。
<div id="grid"></div>
import Handsontable from 'handsontable';
import 'handsontable/styles/handsontable.min.css';
import 'handsontable/styles/ht-theme-main.min.css';
const container = document.getElementById('grid');
new Handsontable(container, {
data: [
['商品名', '単価', '在庫数'],
['りんご', 150, 120],
['みかん', 80, 300],
['バナナ', 100, 85],
],
rowHeaders: true,
colHeaders: true,
height: 'auto',
licenseKey: 'non-commercial-and-evaluation',
});
これだけで、セルをダブルクリックして編集したり、範囲選択してコピー&ペーストしたりできる表が表示されます。Excelからセル範囲をコピーして、そのまま貼り付けることも可能です。この「Excelとの相互コピペ」が現場で驚くほど喜ばれます。
Reactでの使い方
Reactでは HotTable コンポーネントを使います。設定オプションはすべてpropsとして渡します。
import { HotTable } from '@handsontable/react-wrapper';
import { registerAllModules } from 'handsontable/registry';
import 'handsontable/styles/handsontable.min.css';
import 'handsontable/styles/ht-theme-main.min.css';
// すべてのモジュールを一括登録
registerAllModules();
export default function InventoryGrid() {
return (
<HotTable
data={[
['りんご', 150, 120],
['みかん', 80, 300],
['バナナ', 100, 85],
]}
colHeaders={['商品名', '単価', '在庫数']}
rowHeaders={true}
height="auto"
licenseKey="non-commercial-and-evaluation"
/>
);
}
registerAllModules() は全機能を一括で有効化する関数です。バンドルサイズを絞りたい場合は、必要なモジュールだけを個別に登録することもできます。
実践的なユースケース
ここからは、業務システムでよくある「在庫管理表」を想定した実践例です。列ごとの型定義、バリデーション、ドロップダウン、変更検知を組み合わせます。
import { useRef } from 'react';
import { HotTable } from '@handsontable/react-wrapper';
import { registerAllModules } from 'handsontable/registry';
import 'handsontable/styles/handsontable.min.css';
import 'handsontable/styles/ht-theme-main.min.css';
registerAllModules();
const initialData = [
{ name: 'りんご', category: '果物', price: 150, stock: 120 },
{ name: 'みかん', category: '果物', price: 80, stock: 300 },
{ name: 'キャベツ', category: '野菜', price: 200, stock: 45 },
];
export default function InventoryManager() {
const hotRef = useRef(null);
return (
<HotTable
ref={hotRef}
data={initialData}
columns={[
{ data: 'name', title: '商品名' },
{
data: 'category',
title: 'カテゴリ',
type: 'dropdown',
source: ['果物', '野菜', '飲料'],
},
{
data: 'price',
title: '単価',
type: 'numeric',
numericFormat: { pattern: '0,0', culture: 'ja-JP' },
},
{
data: 'stock',
title: '在庫数',
type: 'numeric',
validator: (value, callback) => {
// 在庫数は0以上の整数のみ許可
callback(Number.isInteger(value) && value >= 0);
},
},
]}
rowHeaders={true}
columnSorting={true}
filters={true}
dropdownMenu={true}
afterChange={(changes, source) => {
if (source === 'loadData' || !changes) return;
// 変更されたセルの情報をログ出力(実際はここでAPIに保存)
changes.forEach(([row, prop, oldValue, newValue]) => {
console.log(`${row}行目の${prop}: ${oldValue} → ${newValue}`);
});
}}
height="auto"
licenseKey="non-commercial-and-evaluation"
/>
);
}
このサンプルのポイントを整理します。
type: 'dropdown'- カテゴリ列はドロップダウンから選択させることで、表記ゆれを防ぎますvalidator- 在庫数に負の数や小数が入力されると、セルが赤くハイライトされて弾かれますcolumnSorting/filters/dropdownMenu- 列ヘッダーからソートとフィルタリングができるようになり、Excelのオートフィルタと同じ感覚で使えますafterChange- セルの変更を検知するフックです。ここでAPIを呼べば、編集内容の自動保存が実現できます
数式を使いたい場合
Excel互換の数式が必要なら、同じ開発元が提供する数式エンジンHyperFormulaを組み合わせます。
npm install hyperformula
import { HyperFormula } from 'hyperformula';
new Handsontable(container, {
data: [
['単価', '数量', '小計'],
[150, 3, '=A2*B2'],
[80, 10, '=A3*B3'],
['', '合計', '=SUM(C2:C3)'],
],
formulas: {
engine: HyperFormula,
},
licenseKey: 'non-commercial-and-evaluation',
});
セルに =SUM(C2:C3) のような数式を書くと自動計算され、参照元のセルを編集すれば結果も即座に更新されます。「Excelの数式ごと移行したい」という要望にも応えられるわけです。
まとめ
Handsontableについて、基本から実践的な使い方までを紹介しました。
- Excelライクな操作性(コピペ・キーボード操作・オートフィル)をWebアプリにそのまま持ち込めます
- ドロップダウン、バリデーション、ソート、フィルタなど業務システムに必要な機能が標準で揃っています
- HyperFormulaと組み合わせれば、400以上のExcel互換数式まで使えます
- 商用利用は有料ライセンスが必要な点だけは、導入前に必ず確認しましょう
「Excelで回っている業務をWebに移行したい。でも操作感は落としたくない」——そんな案件を抱えているなら、Handsontableは最有力の選択肢です。まずは非商用ライセンスキーで手元に動くプロトタイプを作り、現場の反応を見てから商用ライセンスを検討する、という進め方がおすすめです。
