Electron
The NodeJS Module can be imported from the main or the renderer thread.
Electron presents a fs
module. The require('xlsx')
call loads the CommonJS
module, so XLSX.readFile
and XLSX.writeFile
work in the renderer thread.
This demo was tested on 2022 November 07 with Electron 21.2.2 on darwin-x64
.
Complete Example (click to show)
This demo includes a drag-and-drop box as well as a file input box, mirroring the SheetJS Data Preview Live Demo
The core data in this demo is an editable HTML table. The readers build up the
table using sheet_to_html
(with editable:true
option) and the writers scrape
the table using table_to_book
.
The demo project is wired for electron-forge
to build the standalone binary.
1) Download the demo files:
package.json
: project structuremain.js
: main process scriptindex.html
: window pageindex.js
: script loaded in render context
Right-click each link and select "Save Link As...". Left-clicking a link will try to load the page in your browser. The goal is to save the file contents.
2) Run npm install
to install dependencies.
3) To verify the app works, run in the test environment:
npx -y electron .
The app will show and you should be able to verify reading and writing by using the relevant buttons to open files and clicking the export button.
4) To build a standalone app, run the builder:
npm run make
This will generate the standalone app in the out\sheetjs-electron-...
folder.
For a recent Intel Mac, the path will be out/sheetjs-electron-darwin-x64/
Writing Files
XLSX.writeFile
writes workbooks to the file system.
showSaveDialog
shows a Save As dialog and returns the selected file name:
/* from the renderer thread */
const electron = require('@electron/remote');
/* this function will show the save dialog and try to write the workbook */
async function exportFile(workbook) {
/* show Save As dialog */
const result = await electron.dialog.showSaveDialog({
title: 'Save file as',
filters: [{
name: "Spreadsheets",
extensions: ["xlsx", "xls", "xlsb", /* ... other formats ... */]
}]
});
/* write file */
XLSX.writeFile(workbook, result.filePath);
}
In older versions of Electron, showSaveDialog
returned the path directly:
var dialog = require('electron').remote.dialog;
function exportFile(workbook) {
var result = dialog.showSaveDialog();
XLSX.writeFile(workbook, result);
}
Reading Files
Electron offers 3 different ways to read files, two of which use Web APIs.
File Input Element
File input elements automatically map to standard Web APIs.
For example, assuming a file input element on the page:
<input type="file" name="xlfile" id="xlf" />
The event handler would process the event as if it were a web event:
async function handleFile(e) {
const file = e.target.files[0];
const data = await file.arrayBuffer();
/* data is an ArrayBuffer */
const workbook = XLSX.read(data);
/* DO SOMETHING WITH workbook HERE */
}
document.getElementById("xlf").addEventListener("change", handleFile, false);
Drag and Drop
The drag and drop snippet applies to DIV elements on the page.
For example, assuming a DIV on the page:
<div id="drop">Drop a spreadsheet file here to see sheet data</div>
The event handler would process the event as if it were a web event:
async function handleDrop(e) {
e.stopPropagation();
e.preventDefault();
const file = e.dataTransfer.files[0];
const data = await file.arrayBuffer();
/* data is an ArrayBuffer */
const workbook = XLSX.read(data);
/* DO SOMETHING WITH workbook HERE */
}
document.getElementById("drop").addEventListener("drop", handleDrop, false);
Electron API
XLSX.readFile
reads workbooks from the file system.
showOpenDialog
shows a Save As dialog and returns the selected file name.
Unlike the Web APIs, the showOpenDialog
flow can be initiated by app code:
/* from the renderer thread */
const electron = require('@electron/remote');
/* this function will show the open dialog and try to parse the workbook */
async function importFile() {
/* show Save As dialog */
const result = await electron.dialog.showOpenDialog({
title: 'Select a file',
filters: [{
name: "Spreadsheets",
extensions: ["xlsx", "xls", "xlsb", /* ... other formats ... */]
}]
});
/* result.filePaths is an array of selected files */
if(result.filePaths.length == 0) throw new Error("No file was selected!");
return XLSX.readFile(result.filePaths[0]);
}
In older versions of Electron, showOpenDialog
returned the path directly:
var dialog = require('electron').remote.dialog;
function importFile(workbook) {
var result = dialog.showOpenDialog({ properties: ['openFile'] });
return XLSX.readFile(result[0]);
}
Electron Breaking Changes
The first version of this demo used Electron 1.7.5. The current demo includes the required changes for Electron 19.2.2.
There are no Electron-specific workarounds in the library, but Electron broke backwards compatibility multiple times. A summary of changes is noted below.
Electron 6.x changed the dialog
API. Methods like showSaveDialog
originally
returned an array of strings, but now returns a Promise
. This change was not
documented.
Electron 9.0.0 and later require the preference nodeIntegration: true
in order
to require('xlsx')
in the renderer process.
Electron 12.0.0 and later also require worldSafeExecuteJavascript: true
and
contextIsolation: true
.
Electron 14+ must use @electron/remote
instead of remote
. An initialize
call is required to enable Developer Tools in the window.