tech-book-labs
データ基盤(クライアント完結) · 最終検証 2026-05-26 · exceljs 4.4.0 · 初公開 2026-05-10

ExcelJS で .xlsx をブラウザで生成・ダウンロードする

ExcelJS でブラウザ完結に Excel ファイルを作成し、ヘッダ装飾 / 数式 / 通貨書式 / 集計行を最小コードで組み立てるパターン。ARGB の alpha 桁、writeBuffer の Browser/Node 差、numFmt の番号書式コード、mergeCells 後の値設定が無視される罠まで実装メモ。

exceljs xlsx spreadsheet browser

検証日: 2026-05-26

使用バージョン: exceljs@4.4.0(2026-05 時点で latest)

対象: ブラウザでユーザに .xlsx をダウンロードさせたい / Node 上で帳票生成したい場面

ExcelJS で .xlsx をブラウザ完結で生成・ダウンロード するパターン。書式付きセル / 数式 / 複数シート / 画像埋め込み / Node 出力までを動く demo で確認します。

触って試す

ヘッダ装飾 + 数式 (=C2*D2 / =SUM) + 通貨書式 ¥ 付きで Excel ファイルを生成。

ボタンを押すと、装飾ヘッダ + 数式 + 通貨書式付きの xlsx が生成されてダウンロードされる。

セットアップ(npm 1 行 / Node + Browser 同 API)

npm i exceljs
項目
公開バージョン4.4.0
Node 必要バージョン18+
TypeScript 型本体同梱(別途 @types/exceljs は不要、deprecated)
ブラウザ対応UMD bundle 同梱(exceljs/dist/exceljs.min.js)、ESM でも import 可
バンドル影響min+gzip で 200KB 前後(フォントサブセット内部リソースあり)、main bundle に同梱せず動的 import 推奨
ライセンスMIT

ブラウザで使うなら import ExcelJS from "exceljs"。Vite / webpack で警告が出る場合は optimizeDeps.includeexceljs を入れる。Cloudflare Workers のような Web API しかない実行環境 では fs 依存の writeFile は使えないので、writeBuffer() + Response で配信する形になる(後述)。

最小サンプル(ExcelJS 4.4、ブラウザで 5 ステップ)

ワークブックを 1 つ作って、ヘッダ + 行を流し込み、Blob 化して .xlsx をダウンロードするまでの最小コード:

import ExcelJS from "exceljs";

const wb = new ExcelJS.Workbook();
const sheet = wb.addWorksheet("Report");

sheet.columns = [
  { header: "ID", key: "id", width: 8 },
  { header: "Name", key: "name", width: 24 },
  { header: "Total", key: "total", width: 12 },
];

sheet.addRow({ id: 1, name: "Alice", total: 1500 });
sheet.addRow({ id: 2, name: "Bob", total: 1100 });

const buf = await wb.xlsx.writeBuffer();
const blob = new Blob([buf], {
  type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
});
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "report.xlsx";
a.click();
URL.revokeObjectURL(url);

writeBuffer()ArrayBuffer を取得 → Blob でダウンロード。

装飾 2 種(ヘッダ太字 + 背景色 ARGB)

ヘッダ行の font を太字に、塗りつぶしを pattern: "solid" で指定:

sheet.getRow(1).font = { bold: true };
sheet.getRow(1).fill = {
  type: "pattern",
  pattern: "solid",
  fgColor: { argb: "FFE2E8F0" },  // 8 桁 ARGB(先頭は alpha = FF)
};

ARGB の先頭 2 桁は alpha(FF = 不透明)。HTML の hex とは桁数が違うので注意。

数式 + 集計(SUM の 2 パターン)

セル値の代わりに { formula: "..." } を渡すと、Excel で開いた時に計算式として扱われる:

sheet.addRow({
  id: 1, qty: 5, price: 200,
  total: { formula: "C2*D2" },     // セル参照
});

sheet.addRow({
  id: "", qty: { formula: "SUM(C2:C10)" }, price: "",
  total: { formula: "SUM(E2:E10)" },
});

{ formula: "..." } で数式を埋める。Excel が開いた時に値が自動計算される。

数値書式 3 種(通貨 / パーセント / 日付)

列単位で numFmt(Excel の番号書式コード)を当てると、各セルの表示が一括で揃う:

sheet.getColumn("price").numFmt = '"¥"#,##0';
sheet.getColumn("rate").numFmt = "0.00%";
sheet.getColumn("date").numFmt = "yyyy/mm/dd";

Excel の番号書式コードがそのまま使える。

罫線 4 辺 + mergeCells

全セルに罫線を引いて、ヘッダ行は mergeCells で 1 行ぶん結合:

// すべてのセルに罫線
sheet.eachRow((row) => {
  row.eachCell((cell) => {
    cell.border = {
      top: { style: "thin" }, bottom: { style: "thin" },
      left: { style: "thin" }, right: { style: "thin" },
    };
  });
});

// セルマージ
sheet.mergeCells("A1:C1");

CSV ↔ xlsx の 2 方向変換

wb.csv / wb.xlsx でフォーマット間を相互変換できる(Node 想定、stream API):

// CSV を xlsx に
const wb = new ExcelJS.Workbook();
await wb.csv.read(stream);  // Node の Readable Stream
await wb.xlsx.writeFile("out.xlsx");

// xlsx を CSV に
await wb.xlsx.readFile("in.xlsx");
await wb.csv.writeFile("out.csv");

Cloudflare Workers / Edge で 1 endpoint .xlsx 配信

exceljswriteBuffer()Buffer | ArrayBuffer を返すので、Node fs を経由せず Response にそのまま流せる:

export async function onRequestGet() {
  const ExcelJS = await import("exceljs");
  const wb = new ExcelJS.Workbook();
  const sheet = wb.addWorksheet("Report");
  sheet.addRow(["id", "name"]);
  sheet.addRow([1, "Alice"]);

  // Node では Buffer、ブラウザ / Workers では ArrayBuffer
  const buf = await wb.xlsx.writeBuffer();

  return new Response(buf, {
    headers: {
      "Content-Type":
        "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
      "Content-Disposition": 'attachment; filename="report.xlsx"',
    },
  });
}

Workers のサイズ制限(1MB scripts、25MB free / 100MB paid)を超えないように、exceljs は dynamic import で route 単位にロードするのが安全。fonts / 画像など重い機能を使わなければ実用範囲に収まる。

7 つの落とし穴と直し方

症状原因直し方
塗りが反映されないARGB の 先頭 2 桁が alphaHTML hex E2E8F0 の前に FF を付けて FFE2E8F0 にする
配列 index で行を指定すると ずれるCell reference は 1-based(C2 = 2 行目)sheet.getRow(1) がヘッダ、getRow(2) が 1 行目データ
writeBuffer() の戻り値が型エラー環境で Buffer (Node) / ArrayBuffer (Browser) が違うBlob([buf]) は両方受け取るので Blob 化してから扱う
数式の参照がズレるaddRow で動的に行が増えると数式の絶対セル参照も追従しないformula を文字列補完で組み立てる(sheet.rowCount で最終行を取って SUM(C2:C + n + ) のように生成)
mergeCells 後に値を入れたのに表示されないマージ後は 左上セル以外の値が無視されるmergeCells する前に値を入れるか、左上セル getCell("A1") に書く
通貨が ¥1,500.00 になってしまうnumFmt のコード末尾に小数指定'"¥"#,##0'(整数)/ '"¥"#,##0.00'(小数 2 桁)を使い分け
10 万行で OOMworkbook を全部 memory に保持wb.xlsx.write(stream) で書き出し(Node)、または xlsx-populate / node-xlsx 等の軽量代替

評価

観点評価コメント
学習コストAPI は分かりやすいが、書式コード仕様(numFmt)に Excel 知識必要
機能網羅装飾 / 数式 / グラフ / 画像 / mergeCells すべて対応
ブラウザ対応Node / browser 同 API
バンドル200KB 前後、フォントサブセットなどの内部リソース大きい
TypeScript型同梱、ただし一部 any

向く / 向かないケース

  • 向く: 帳票出力、レポート PDF と並ぶ業務系出力、ユーザダウンロード機能
  • 向かない: シンプルな CSV 出力(Papa.unparse のほうが軽い)
  • 向かない: 100 万行超(streaming write or 別ツール)

関連 Topic / 関連書籍

この記事と関係する tech-book.net の Topic と、それぞれの Topic に紐づく書籍:

tech-book.net /books/9784297144944

JavaScriptによるはじめてのアルゴリズム入門 | tech-book.net

河西 朝雄

関連テーマ・学習ロードマップから次の一冊へ。

詳細を tech-book.net で見る
tech-book.net /books/9784873118086

Python と JavaScriptではじめるデータビジュアライゼーション | tech-book.net

Kyran Dale/嶋田 健志/木下 哲也

関連テーマ・学習ロードマップから次の一冊へ。

詳細を tech-book.net で見る
tech-book.net /books/9784839966645

React Native+Expoではじめるスマホアプリ開発 : JavaScriptによるアプリ構築の実際 | tech-book.net

松澤 太郎

関連テーマ・学習ロードマップから次の一冊へ。

詳細を tech-book.net で見る
tech-book.net /books/9784627857216

はじめてのWebデザイン&プログラミング : HTML、CSS、JavaScript、PHPの基本 | tech-book.net

村上 祐治

関連テーマ・学習ロードマップから次の一冊へ。

詳細を tech-book.net で見る
tech-book.net /books/9784297138714

フロントエンドの知識地図ーー 一冊でHTML/CSS/JavaScriptの開発技術が学べる本 | tech-book.net

株式会社ICS 池田 泰延/西原 翼/松本 ゆき

関連テーマ・学習ロードマップから次の一冊へ。

詳細を tech-book.net で見る