React + ExcelJSでExcel, CSV, TSVファイルを出力する方法

ExcelJSでExcelやCSVファイルを出力

Reactで作成しているWebサイトまたはWebアプリで、特定のデータをExcel, CSV, TSVファイルで出力してダウンロードしたいことがあります。

そんなときはExcelJSというJavaScriptライブラリを使用すれば簡単にExcel, CSV, TSVファイルで出力できます。

※ ExcelJSという名前ですが、CSVやTSVファイルも出力できます。

React + ExcelJSでExcelを出力する方法

まず、以下のコマンドでVite + Reactの環境を作成します。

npm create vite@latest my-react-exceljs -- --template react-swc-ts

次にcdでプロジェクトディレクトリに移動して、必要なものをインストールします。

cd my-react-exceljs
npm install
npm i -D exceljs

最後にApp.tsxに以下のコードを貼り付けれると、React + ExcelJSでExcelを出力してダウンロードできるWebページが作成できます。

App.tsx
import ExcelJS from 'exceljs'

const App = () => {
  const clickButtonAsync = async (e: React.MouseEvent<HTMLButtonElement>) => {
    e.preventDefault()
    const filename = 'sample.xlsx'
    const workbook = new ExcelJS.Workbook()
    const worksheet = workbook.addWorksheet('My Sheet')

    // ヘッダーを追加
    worksheet.columns = [
      { header: 'ID', key: 'id' },
      { header: '名称', key: 'name' },
      { header: '価格', key: 'price' }
    ]

    // 行を追加
    worksheet.addRows([
      { id: 1001, name: 'りんご', price: 100 },
      { id: 1002, name: 'バナナ', price: 200 },
      { id: 1003, name: 'みかん', price: 300 },
    ])

    // Excelデータをバッファとして取得
    const excelBuffer = await workbook.xlsx.writeBuffer()

    // Blobを作成(MIMEタイプ: Excel)
    const blob = new Blob([excelBuffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
    const url = URL.createObjectURL(blob)
    const a = document.createElement('a')
    a.href = url
    a.download = filename
    a.click()

    // リソースを解放
    URL.revokeObjectURL(url)
  }

  return (
    <div>
      <h1>Download Excel File</h1>
      <button onClick={clickButtonAsync}>Download</button>
    </div>
  )
}

export default App

JavaScriptとReactの基礎が理解できている人であれば、細かく説明しなくてもコードを見ただけで理解していただけるかと思います。

Downloadボタンをクリックすると、Excelファイルがダウンロードできます。

ファイル名を「sample.xlsx」、シート名を「My Sheet」、シート内のデータを配列で追加しているので、それぞれの内容がExcelファイルに反映されていることが確認できます。

React + ExcelJSでCSVを出力する方法

React + ExcelJSでCSVファイルを出力するコードはExcelファイルのときとほとんど同じです。

App.tsx
import ExcelJS from 'exceljs'

const App = () => {
  const clickButtonAsync = async (e: React.MouseEvent<HTMLButtonElement>) => {
    e.preventDefault()
    const filename = 'sample.csv'
    const workbook = new ExcelJS.Workbook()
    const worksheet = workbook.addWorksheet('My Sheet')

    // ヘッダーを追加
    worksheet.columns = [
      { header: 'ID', key: 'id' },
      { header: '名称', key: 'name' },
      { header: '価格', key: 'price' }
    ]

    // 行を追加
    worksheet.addRows([
      { id: 1001, name: 'りんご', price: 100 },
      { id: 1002, name: 'バナナ', price: 200 },
      { id: 1003, name: 'みかん', price: 300 },
    ])

    // CSVデータをバッファとして取得
    const csvBuffer = await workbook.csv.writeBuffer()

    // Blobを作成(MIMEタイプ: text/csv)
    const blob = new Blob([csvBuffer], { type: 'text/csv;charset=utf-8;' })
    const url = URL.createObjectURL(blob)
    const a = document.createElement('a')
    a.href = url
    a.download = filename
    a.click()

    // リソースを解放
    URL.revokeObjectURL(url)
  }

  return (
    <div>
      <h1>Download CSV File</h1>
      <button onClick={clickButtonAsync}>Download</button>
    </div>
  )
}

export default App

Excelのときとの違いは以下の3点だけです。

  1. ファイル名の拡張子をsample.xlsxからsample.csvに変更
  2. バッファをExcelからCSVに変更 (workbook.csv.writeBuffer()になる)
  3. Blob作成時のMIMEタイプをCSVに変更

CSVファイルの生成はExcelJSを使わずにJavaScriptだけでも可能ですが、ExcelJSのCSVのフォーマットにはFast-CSVが内部で使用されています。

Fast-CSVにより「"」のエスケープなどがデフォルトで処理されるので、ExcelJSを使用したほうがCSVファイルの出力が簡単にできます。

Downloadボタンをクリックすると、CSVファイルがダウンロードできます。

ダウンロードしたsample.csvファイルを開くと、以下の内容になっていることが確認できます。

sample.csv
ID,名称,価格
1001,りんご,100
1002,バナナ,200
1003,みかん,300

React + ExcelJSでTSVを出力する方法

React + ExcelJSでTSVファイルを出力するコードはCSVファイルのときとほとんど同じです。

TSX
import ExcelJS from 'exceljs'

const App = () => {
  const clickButtonAsync = async (e: React.MouseEvent<HTMLButtonElement>) => {
    e.preventDefault()
    const filename = 'sample.tsv'
    const workbook = new ExcelJS.Workbook()
    const worksheet = workbook.addWorksheet('My Sheet')

    // ヘッダーを追加
    worksheet.columns = [
      { header: 'ID', key: 'id' },
      { header: '名称', key: 'name' },
      { header: '価格', key: 'price' }
    ]

    // 行を追加
    worksheet.addRows([
      { id: 1001, name: 'りんご', price: 100 },
      { id: 1002, name: 'バナナ', price: 200 },
      { id: 1003, name: 'みかん', price: 300 }
    ])

    // タブ区切りのオプション
    const options = {
      formatterOptions: {
        delimiter: '\t'
      }
    }

    // CSVデータをバッファとして取得(TSV形式)
    const tsvBuffer = await workbook.csv.writeBuffer(options)

    // Blobを作成(MIMEタイプ: text/tab-separated-values)
    const blob = new Blob([tsvBuffer], { type: 'text/tab-separated-values;charset=utf-8;' })
    const url = URL.createObjectURL(blob)
    const a = document.createElement('a')
    a.href = url
    a.download = filename
    a.click()

    // リソースを解放
    URL.revokeObjectURL(url)
  }

  return (
    <div>
      <h1>Download TSV File</h1>
      <button onClick={clickButtonAsync}>Download</button>
    </div>
  )
}

export default App

CSVのときとの違いは以下の3点だけです。

  1. ファイル名の拡張子をsample.csvからsample.tsvに変更
  2. formatterOptionsで区切り文字を「delimiter: '\t'」に変更
  3. Blob作成時のMIMEタイプをTSVに変更

バッファをworkbook.tsv.writeBufferにしないよう注意してください。

ExcelJSはTSVを正式にサポートしていないので、CSVファイルの区切り文字をタブ (delimiter: '\t') にして、MIMEタイプをTSVに変更することでTSVファイルとして出力しています。

sample.tsvファイルを開くと以下のようにカンマではなくタブで区切られています。

sample.tsv
ID	名称	価格
1001	りんご	100
1002	バナナ	200
1003	みかん	300

ExcelJSのformatterOptions

ExcelJSでは内部でFast-CSVを使用しているので、区切り文字などをオプションで変更することができます。

CSVとして出力するならオプションの変更は不要ですが、前述のTSVファイルの書き出しのようにCSVの形式を特別な理由があって変更する必要があるときは、これらのオプションが役立ちます。

以降にExcelJSでCSVのフォーマットに使用可能なオプションを記載しましたので、参考にしてください。

delimiter

delimiterオプションを指定することで、デフォルトの区切り文字を「,」から別の文字に変更できます。

タブに変更したい場合は、先程のTSVのコードのように delimiter: '\t' を指定します。

TSX
const options = {
  formatterOptions: {
    delimiter: '\t'
  }
}
const tsvBuffer = await workbook.csv.writeBuffer(options)

rowDelimiter

rowDelimiterオプションを指定することで、デフォルトの行区切り記号「\n」を変更できます。

主に区切り記号を「\r」や「\r\n」に変更したいときに使用します。

TSX
const options = {
  formatterOptions: {
    rowDelimiter: '\r\n'
  }
}
const tsvBuffer = await workbook.csv.writeBuffer(options)

quote

quoteオプションを指定することで、デフォルトのquote「"」を変更することができます。

例えば「quote: "'"」を指定すれば、ダブルクォーテーションではなくシングルクォーテーションが使用されます。

TSX
const options = {
  formatterOptions: {
    quote: "'"
  }
}
const tsvBuffer = await workbook.csv.writeBuffer(options)
sample.csv
ID,名称,価格
1001,りんご,'1,000'
1002,バナナ,'2,000'
1003,みかん,'3,000'

escape

escapeオプションでデフォルトのエスケープ文字「"」を変更できます。

デフォルトではダブルクォーテーションはダブルクォーテーションでエスケープを使用しますが、escapeを使用することでバックスラッシュなどに変更できます。

TSX
worksheet.addRows([
  { id: 1001, name: 'りんご "TEST"', price: 100 },
  { id: 1002, name: 'バナナ "TEST"', price: 200 },
  { id: 1003, name: 'みかん "TEST"', price: 300 },
])
const options = {
  formatterOptions: {
    escape: '\\'
  }
}
const csvBuffer = await workbook.csv.writeBuffer(options)
sample.csv
ID,名称,価格
1001,"りんご \"TEST\"",100
1002,"バナナ \"TEST\"",200
1003,"みかん \"TEST\"",300

writeBOM

ExcelJSではデフォルトではファイルはUTF-8になっています。

UTF-8 BOMにしたい場合はオプションで「writeBOM: true」を追加します。

TSX
const options = {
  formatterOptions: {
    writeBOM: true
  }
}
const csvBuffer = await workbook.csv.writeBuffer(options)

Shift_JISにしたい場合は「npm i iconv-lite」でiconvをインストールして、エンコードをUTF-8からShift_JISに変更してください。

TSX
// CSVデータをバッファとして取得(UTF-8)
const csvBuffer = await workbook.csv.writeBuffer()
const utf8String = csvBuffer.toString()
const sjisBuffer = iconv.encode(utf8String, 'Shift_JIS')

// Blobを作成(Shift_JIS エンコード)
const blob = new Blob([sjisBuffer], { type: 'text/csv' })

quoteColumns

常にダブルクォーテーションで囲むようにできるオプションです。

quoteColumns: true を指定することで、すべてがダブルクォーテーションで囲まれます。

TSX
const options = {
  formatterOptions: {
    quoteColumns: true
  }
}
const csvBuffer = await workbook.csv.writeBuffer(options)
sample.csv
"ID","名称","価格"
"1001","りんご","100"
"1002","バナナ","200"
"1003","みかん","300"

配列やオブジェクトを使用することで、特定の列のみダブルクォーテーションを適用させることもできます。

TSX
const options = {
  formatterOptions: {
    quoteColumns: {
      '価格': true // または [false, false, true]
    }
  }
}
const csvBuffer = await workbook.csv.writeBuffer(options)
sample.csv
ID,名称,"価格"
1001,りんご,"100"
1002,バナナ,"200"
1003,みかん,"300"

headersとquoteHeaders

headersとquoteHeadersをtrueにすると、ヘッダーのみダブルクォーテーションを適用できます。

TSX
const options = {
  formatterOptions: {
    headers: true,
    quoteHeaders: true,
  }
}
const csvBuffer = await workbook.csv.writeBuffer(options)
sample.csv
"ID","名称","価格"
1001,りんご,100
1002,バナナ,200
1003,みかん,300

map

指定したindex (列) を編集することができます。

例えばヘッダーを除く1列目 (index: 0) から1000を引いて、3列目 (index: 2) に円の文字を追加する場合は以下のようになります。

TSX
const options = {
  if (value === 'ID' || value === '価格') return value
  map(value: number | string, index: number) {
    switch(index) {
      case 0:
        return +value - 1000;
      case 2:
        return value + '';
      default:
        return value;
    }
  },
}
const csvBuffer = await workbook.csv.writeBuffer(options)
sample.csv
ID,名称,価格
1,りんご,100
2,バナナ,200
3,みかん,300

まとめ

React + ExcelJSを使用すれば、簡単にExcel, CSV, TSVファイルを出力(ダウンロード)できます。

CSVファイルの出力に関してはオプションで区切り文字やエスケープ文字などを変更することができます。

しかし、デフォルトの状態から変更すると、CSVファイルの一般的書式 (RFC4180)と異なってしまい、Excelなどで正しく表示できなくなってしまうことがあるので、特に理由がなければ変更しないほうが良いです。