はじめに
大量の行を持つテーブルをブラウザに表示しようとして、スクロールがカクついたり、タブごとフリーズしたりした経験はないでしょうか。DOMに全行を描画してしまうと、数千行を超えたあたりから描画コストが跳ね上がり、ユーザー体験を大きく損ないます。
RevoGridは、この「大量データ × テーブル表示」という課題に、仮想スクロールという仕組みで正面から向き合ったデータグリッドライブラリです。表示領域に映る行だけをDOMに描画することで、100万行規模のデータでも軽快な操作感を保ちます。しかもStencilJSで作られたWeb Componentなので、React・Vue・Angular・Svelte、そしてフレームワークを使わないVanilla JavaScriptからも同じ<revo-grid>タグとして扱えます。
とはいえ、読むより触った方が早いと思います。検索ボックスを打つとその場で表示行が絞り込まれる、実際に動くRevoGridのグリッドを用意したので、先に挙動を見たい方はこちらからどうぞ。
RevoGridとは
RevoGridは、revolistが開発しているオープンソースのデータグリッドコンポーネントです。内部はStencilJSで実装されており、コンパイル後は標準のWeb Componentとして配布されます。そのため特定のフレームワークに縛られず、<revo-grid>というカスタム要素をHTMLに置くだけでどこでも動作します。
主な特徴
- 仮想スクロールによる高速レンダリング - 表示領域に入る行・列だけをDOMに描画するため、100万行クラスのデータでもスクロールが滑らかです
- フレームワーク非依存 - React・Vue 2/3・Angular・Svelte向けのラッパーが用意されているほか、Vanilla JavaScriptからも直接カスタム要素として利用できます
- Excelライクな操作性 - セル範囲選択、コピー&ペースト、キーボードでのフォーカス移動など、表計算ソフトに近い操作感を再現しています
- 組み込みのソート・フィルタリング・編集 -
sortableやfilter、readonlyといったプロパティを設定するだけで、代表的なグリッド機能を有効化できます - アクセシビリティとRTL対応 - WAI-ARIAに準拠しており、アラビア語やヘブライ語などの右から左に書く言語も扱えます
インストール
npmまたはyarnで@revolist/revogridパッケージを追加します。
npm install @revolist/revogrid --save
yarn add @revolist/revogrid
React・Vue・Angular向けのフレームワークバインディングを使う場合は、それぞれ@revolist/react-datagridや公式ドキュメントで案内されているアダプタを追加で利用します。本記事ではまず土台となるVanilla JavaScriptでの使い方を中心に解説します。
RevoGridのサンプルを動かす
RevoGridはWeb Componentとして提供されているため、defineCustomElement()を呼び出すだけで<revo-grid>タグが使えるようになります。あとはcolumnsプロパティに列定義、sourceプロパティに行データの配列を渡すだけです。下のサンプルでは検索ボックスに入力すると、grid.sourceを書き換えることで表示行がその場で絞り込まれます。
import { defineCustomElement } from '@revolist/revogrid/standalone/revo-grid.js'
defineCustomElement()
const grid = document.querySelector('revo-grid')
grid.columns = [
{ prop: 'name', name: '名前' },
{ prop: 'role', name: '役職' },
]
grid.source = [
{ name: 'Ada Lovelace', role: '数学者' },
{ name: 'Grace Hopper', role: '計算機科学者' },
]
実際に検索ボックスへ「Ada」や「科学者」と入力してみてください。source配列をフィルタして再代入するだけで、RevoGrid側が仮想スクロールに合わせて再描画してくれます。
このように、RevoGrid自体はデータの持ち方に関知しません。sourceに配列を渡し直すだけで再描画されるので、検索・並び替え・APIからの再取得など、どんなデータ更新パターンとも組み合わせやすいのが特徴です。
基本的な使い方
RevoGridを組み込む最小構成は、次の3ステップです。
defineCustomElement()でカスタム要素<revo-grid>を登録するcolumnsプロパティに列のprop(データのキー)とname(表示名)を指定するsourceプロパティに行データの配列を渡す
<revo-grid id="grid" style="height: 300px"></revo-grid>
<script type="module">
import { defineCustomElement } from '@revolist/revogrid/standalone/revo-grid.js'
defineCustomElement()
const grid = document.getElementById('grid')
grid.columns = [
{ prop: 'id', name: 'ID', readonly: true },
{ prop: 'name', name: '商品名' },
{ prop: 'price', name: '価格' },
]
grid.source = [
{ id: 1, name: 'Apple', price: 120 },
{ id: 2, name: 'Banana', price: 80 },
]
</script>
readonly: trueを指定した列は編集不可になります。逆に言えば、指定しない限りすべてのセルはデフォルトで編集可能です。この挙動は次の「実践的なユースケース」でも扱います。
実践的なユースケース
RevoGridは「並び替え」「絞り込み」「編集」という、業務アプリでテーブルを使うときに必ず求められる3つの機能を、それぞれ独立したオプションとして持っています。パターンごとに見ていきましょう。
RevoGridでヘッダーソートを有効にする
一覧画面で「価格が高い順に見たい」というニーズに応えるのがソート機能です。RevoGridでは列定義にsortable: trueを指定するだけで、ヘッダークリックによる昇順・降順の切り替えが有効になります。初期表示順を決めたい場合はorderに'asc'または'desc'を指定します。
grid.columns = [
{ prop: 'name', name: '名前', sortable: true },
{ prop: 'score', name: 'スコア', sortable: true, order: 'desc' },
]
下のサンプルでは「名前」と「スコア」の両列にソートを設定しています。列ヘッダーをクリックすると昇順・降順・解除の順に切り替わります。
score列はorder: 'desc'を指定しているため、初期表示時点でスコアの高い順に並んでいます。列ヘッダーの▲/▼アイコンをクリックすると、name列やscore列のソート方向がその場で切り替わるのを確認できます。
RevoGridで列フィルタを使う
一覧が長くなるほど、ソートだけでは目的の行にたどり着きにくくなります。RevoGridではグリッド全体のfilterプロパティをtrueにし、各列のfilterに'string'(文字列検索)や'number'(数値比較)を指定することで、列ヘッダーにフィルタアイコンが表示されるようになります。
grid.filter = true
grid.columns = [
{ prop: 'name', name: '名前', filter: 'string' },
{ prop: 'price', name: '価格', filter: 'number' },
]
下のサンプルでは「価格」列の右端にあるフィルタアイコンをクリックすると、「より大きい」「以下」といった数値条件を選んで絞り込めます。
filter: 'number'を指定した列では「greater than」「less than」といった数値演算子がフィルタの選択肢に現れます。filter: 'string'側では部分一致検索が使えるため、列ごとにデータの性質に合わせたフィルタを組み合わせられるのがポイントです。
RevoGridでセル編集を検証する
RevoGridはreadonlyを指定しない限りセルが編集可能ですが、実務では「不正な値を弾く」処理も欠かせません。RevoGridは編集確定前に発火するbeforeeditイベントを提供しており、event.preventDefault()を呼べば編集の反映そのものを取り消せます。
grid.addEventListener('beforeedit', (e) => {
const { prop, val } = e.detail
if (prop === 'price' && Number(val) < 0) {
e.preventDefault() // マイナスの価格を拒否
}
})
下のサンプルでは「価格」セルをダブルクリックして編集し、マイナスの値を入力してEnterを押してみてください。編集が拒否され、画面下にメッセージが表示されます。
beforeeditでpreventDefault()すると、その編集はsourceに一切反映されません。正常な値であればaftereditが発火し、確定後の値をコンソールで確認できます。バリデーションをUI側の入力制限だけに頼らず、データの出入り口であるイベントで検証できる点は、業務システムにRevoGridを組み込むうえで安心材料になります。
まとめ
RevoGridは、仮想スクロールによる高いパフォーマンスと、Web Componentとしてのフレームワーク非依存性を両立したデータグリッドです。columnsとsourceを渡すだけの最小構成から、ソート・フィルタリング・セル編集のバリデーションまで、プロパティとイベントの組み合わせで段階的に機能を積み上げられる設計になっています。
大量データを扱う管理画面やダッシュボードでテーブル表示のパフォーマンスに悩んでいるなら、まずは今回のサンプルを手元で書き換えて、RevoGridの挙動を試してみてください。