Import & Export

SpreadJS supports the opening and saving to several popular file formats including Excel .xlsx/.xlsm/.xltm/.xltx, .csv, .ssjson (older SpreadJS format) and the new faster .sjs SpreadJS file formats. The new .sjs format significantly improves the load time and memory usage when working with very large Excel files while greatly reducing the file size when resaved as compared to previous SpreadJS versions.

Learn more about opening password protected Excel files.

In order to use the SpreadJS File Format feature, you need to add the related js file link into the document's head section below the Spread link. For example: SpreadJS supports opening and saving sjs file formats. It also supports importing and exporting xlsx, xlsm, xltm, xltx, ssjson, and csv file formats. For example: class GC.Spread.Sheets.Workbook GC.Spread.Sheets.SaveOptions GC.Spread.Sheets.OpenOptions GC.Spread.Sheets.ImportOptions GC.Spread.Sheets.ExportOptions GC.Spread.Sheets.ExcelFileType GC.Spread.Sheets.ImportXlsxOptions GC.Spread.Sheets.ExportXlsxOptions GC.Spread.Sheets.ImportCsvOptions .Spread.Sheets.ExportCsvOptions GC.Spread.Sheets.ImportSSJsonOptions GC.Spread.Sheets.ExportSSJsonOptions
<template> <div class="sample-tutorial"> <div class="sample-container"> <gc-spread-sheets class="sample-spreadsheets" @workbookInitialized="initSpread"> <gc-worksheet> </gc-worksheet> </gc-spread-sheets> <div id="statusBar"></div> </div> <aside class="options-container" aria-label="SpreadJS file format settings"> <div class="panel-header"> <h1>File Format Settings</h1> <p class="panel-description">Open and save SpreadJS file or Excel file with format-specific import and export options.</p> </div> <div class="option-row"> <section class="inputContainer control-section"> <h2>Open File</h2> <div class="file-action-row"> <label for="selectedFile">Source File</label> <input id="selectedFile" type="file" accept=".sjs, .xlsx, .xlsm, .xltm, .xltx, .ssjson, .json, .csv" v-on:change="selectedFileChange($event)" /> <button class="settingButton" id="open" v-on:click="open">Open</button> </div> <div class="open-options"> <div class="item" v-show="needShow('open', 'openMode')"> <label for="open-openMode">{{ formatOptionLabel('openMode') }}</label> <select id="open-openMode" v-model.number="openOptions.openMode"> <option value="0">normal</option> <option value="1">lazy</option> <option value="2">incremental</option> </select> </div> <div class="item" v-show="needShow('open', 'includeStyles')" > <input type="checkbox" id="open-includeStyles" v-model="openOptions.includeStyles"/> <label for="open-includeStyles">{{ formatOptionLabel('includeStyles') }}</label> </div> <div class="item" v-show="needShow('open', 'includeFormulas')" > <input type="checkbox" id="open-includeFormulas" v-model="openOptions.includeFormulas"/> <label for="open-includeFormulas">{{ formatOptionLabel('includeFormulas') }}</label> </div> <div class="item" v-show="needShow('open', 'frozenColumnsAsRowHeaders')" > <input type="checkbox" id="open-frozenColumnsAsRowHeaders" v-model="openOptions.frozenColumnsAsRowHeaders"/> <label for="open-frozenColumnsAsRowHeaders">{{ formatOptionLabel('frozenColumnsAsRowHeaders') }}</label> </div> <div class="item" v-show="needShow('open', 'frozenRowsAsColumnHeaders')" > <input type="checkbox" id="open-frozenRowsAsColumnHeaders" v-model="openOptions.frozenRowsAsColumnHeaders"/> <label for="open-frozenRowsAsColumnHeaders">{{ formatOptionLabel('frozenRowsAsColumnHeaders') }}</label> </div> <div class="item" v-show="needShow('open', 'fullRecalc')" > <input type="checkbox" id="open-fullRecalc" v-model="openOptions.fullRecalc"/> <label for="open-fullRecalc">{{ formatOptionLabel('fullRecalc') }}</label> </div> <div class="item" v-show="needShow('open', 'dynamicReferences')" > <input type="checkbox" id="open-dynamicReferences" v-model="openOptions.dynamicReferences"/> <label for="open-dynamicReferences">{{ formatOptionLabel('dynamicReferences') }}</label> </div> <div class="item" v-show="needShow('open', 'incrementalCalculation')" > <input type="checkbox" id="open-incrementalCalculation" v-model="openOptions.incrementalCalculation"/> <label for="open-incrementalCalculation">{{ formatOptionLabel('incrementalCalculation') }}</label> </div> <div class="item" v-show="needShow('open', 'includeUnusedStyles')" > <input type="checkbox" id="open-includeUnusedStyles" v-model="openOptions.includeUnusedStyles"/> <label for="open-includeUnusedStyles">{{ formatOptionLabel('includeUnusedStyles') }}</label> </div> <div class="item" v-show="needShow('open', 'convertSheetTableToDataTable')" > <input type="checkbox" id="open-convertSheetTableToDataTable" v-model="openOptions.convertSheetTableToDataTable"/> <label for="open-convertSheetTableToDataTable">{{ formatOptionLabel('convertSheetTableToDataTable') }}</label> </div> <div class="item" v-show="needShow('open', 'incrementalLoading')" > <input type="checkbox" id="open-incrementalLoading" v-model="openOptions.incrementalLoading"/> <label for="open-incrementalLoading">{{ formatOptionLabel('incrementalLoading') }}</label> </div> <div class="item" v-show="needShow('open', 'encoding')" > <label for="open-encoding">{{ formatOptionLabel('encoding') }}</label> <input type="text" id="open-encoding" v-model="openOptions.encoding"/> </div> <div class="item" v-show="needShow('open', 'rowDelimiter')" > <label for="open-rowDelimiter">{{ formatOptionLabel('rowDelimiter') }}</label> <input type="text" id="open-rowDelimiter" v-model="openOptions.rowDelimiter"/> </div> <div class="item" v-show="needShow('open', 'columnDelimiter')" > <label for="open-columnDelimiter">{{ formatOptionLabel('columnDelimiter') }}</label> <input type="text" id="open-columnDelimiter" v-model="openOptions.columnDelimiter"/> </div> </div> </section> <section class="inputContainer control-section"> <h2>Save File</h2> <div class="save-action-row"> <label for="saveFileType">File Type</label> <select id="saveFileType" v-model="saveFileType"> <option value="sjs">SJS</option> <option value="xlsx">Excel</option> <option value="ssjson">SSJson</option> <option value="csv">Csv</option> </select> <button class="settingButton" id="save" v-on:click="save">Save</button> </div> <div class="excelFileTypeContainer" v-show="showExcelFileType()"> <label for="saveExcelFileType">Excel File Type</label> <div> <select id="saveExcelFileType" v-model="excelFileType"> <option value="XLSX">Workbook (*.xlsx)</option> <option value="XLSM">Macro-Enabled Workbook (*.xlsm)</option> <option value="XLTM">Macro-Enabled Template (*.xltm)</option> <option value="XLTX">Workbook Template (*.xltx)</option> </select> </div> </div> <div class="save-options"> <div class="item" v-show="needShow('save', 'includeBindingSource')" > <input type="checkbox" id="save-includeBindingSource" v-model="saveOptions.includeBindingSource"/> <label for="save-includeBindingSource">{{ formatOptionLabel('includeBindingSource') }}</label> </div> <div class="item" v-show="needShow('save', 'includeStyles')" > <input type="checkbox" id="save-includeStyles" v-model="saveOptions.includeStyles"/> <label for="save-includeStyles">{{ formatOptionLabel('includeStyles') }}</label> </div> <div class="item" v-show="needShow('save', 'includeFormulas')" > <input type="checkbox" id="save-includeFormulas" v-model="saveOptions.includeFormulas"/> <label for="save-includeFormulas">{{ formatOptionLabel('includeFormulas') }}</label> </div> <div class="item" v-show="needShow('save', 'saveAsView')" > <input type="checkbox" id="save-saveAsView" v-model="saveOptions.saveAsView"/> <label for="save-saveAsView">{{ formatOptionLabel('saveAsView') }}</label> </div> <div class="item" v-show="needShow('save', 'rowHeadersAsFrozenColumns')" > <input type="checkbox" id="save-rowHeadersAsFrozenColumns" v-model="saveOptions.rowHeadersAsFrozenColumns"/> <label for="save-rowHeadersAsFrozenColumns">{{ formatOptionLabel('rowHeadersAsFrozenColumns') }}</label> </div> <div class="item" v-show="needShow('save', 'columnHeadersAsFrozenRows')" > <input type="checkbox" id="save-columnHeadersAsFrozenRows" v-model="saveOptions.columnHeadersAsFrozenRows"/> <label for="save-columnHeadersAsFrozenRows">{{ formatOptionLabel('columnHeadersAsFrozenRows') }}</label> </div> <div class="item" v-show="needShow('save', 'includeAutoMergedCells')" > <input type="checkbox" id="save-includeAutoMergedCells" v-model="saveOptions.includeAutoMergedCells"/> <label for="save-includeAutoMergedCells">{{ formatOptionLabel('includeAutoMergedCells') }}</label> </div> <div class="item" v-show="needShow('save', 'includeCalcModelCache')" > <input type="checkbox" id="save-includeCalcModelCache" v-model="saveOptions.includeCalcModelCache"/> <label for="save-includeCalcModelCache">{{ formatOptionLabel('includeCalcModelCache') }}</label> </div> <div class="item" v-show="needShow('save', 'saveR1C1Formula')" > <input type="checkbox" id="save-saveR1C1Formula" v-model="saveOptions.saveR1C1Formula"/> <label for="save-saveR1C1Formula">{{ formatOptionLabel('saveR1C1Formula') }}</label> </div> <div class="item" v-show="needShow('save', 'includeUnusedNames')" > <input type="checkbox" id="save-includeUnusedNames" v-model="saveOptions.includeUnusedNames"/> <label for="save-includeUnusedNames">{{ formatOptionLabel('includeUnusedNames') }}</label> </div> <div class="item" v-show="needShow('save', 'includeEmptyRegionCells')" > <input type="checkbox" id="save-includeEmptyRegionCells" v-model="saveOptions.includeEmptyRegionCells"/> <label for="save-includeEmptyRegionCells">{{ formatOptionLabel('includeEmptyRegionCells') }}</label> </div> <div class="item" v-show="needShow('save', 'losslessEditing')" > <input type="checkbox" id="save-losslessEditing" v-model="saveOptions.losslessEditing"/> <label for="save-losslessEditing">{{ formatOptionLabel('losslessEditing') }}</label> </div> <div class="item" v-show="needShow('save', 'encoding')" > <label for="save-encoding">{{ formatOptionLabel('encoding') }}</label> <input type="text" id="save-encoding" v-model="saveOptions.encoding"/> </div> <div class="item" v-show="needShow('save', 'rowDelimiter')" > <label for="save-rowDelimiter">{{ formatOptionLabel('rowDelimiter') }}</label> <input type="text" id="save-rowDelimiter" v-model="saveOptions.rowDelimiter"/> </div> <div class="item" v-show="needShow('save', 'columnDelimiter')" > <label for="save-columnDelimiter">{{ formatOptionLabel('columnDelimiter') }}</label> <input type="text" id="save-columnDelimiter" v-model="saveOptions.columnDelimiter"/> </div> <div class="item" v-show="needShow('save', 'sheetIndex')" > <label for="save-sheetIndex">{{ formatOptionLabel('sheetIndex') }}</label> <input type="number" id="save-sheetIndex" v-model.number="saveOptions.sheetIndex"/> </div> <div class="item" v-show="needShow('save', 'row')" > <label for="save-row">{{ formatOptionLabel('row') }}</label> <input type="number" id="save-row" v-model.number="saveOptions.row"/> </div> <div class="item" v-show="needShow('save', 'column')" > <label for="save-column">{{ formatOptionLabel('column') }}</label> <input type="number" id="save-column" v-model.number="saveOptions.column"/> </div> <div class="item" v-show="needShow('save', 'rowCount')" > <label for="save-rowCount">{{ formatOptionLabel('rowCount') }}</label> <input type="number" id="save-rowCount" v-model.number="saveOptions.rowCount"/> </div> <div class="item" v-show="needShow('save', 'columnCount')" > <label for="save-columnCount">{{ formatOptionLabel('columnCount') }}</label> <input type="number" id="save-columnCount" v-model.number="saveOptions.columnCount"/> </div> </div> </section> </div> </aside> </div> </template> <script setup> import GC from "@mescius/spread-sheets"; import { ref, toRaw } from "vue"; import '@mescius/spread-sheets-print'; import "@mescius/spread-sheets-vue"; import "@mescius/spread-sheets-io"; import '@mescius/spread-sheets-shapes'; import '@mescius/spread-sheets-charts'; import '@mescius/spread-sheets-slicers'; import '@mescius/spread-sheets-pivot-addon'; import '@mescius/spread-sheets-reportsheet-addon'; import "@mescius/spread-sheets-tablesheet"; import "@mescius/spread-sheets-ganttsheet"; const openOptions = { openMode: 0, includeStyles: true, includeFormulas: true, frozenColumnsAsRowHeaders: false, frozenRowsAsColumnHeaders: false, fullRecalc: false, dynamicReferences: true, incrementalCalculation: false, includeUnusedStyles: true, convertSheetTableToDataTable: false, incrementalLoading: false, encoding: "UTF-8", rowDelimiter: "\r\n", columnDelimiter: "," }; const saveOptions = { includeBindingSource: false, includeStyles: true, includeFormulas: true, saveAsView: false, rowHeadersAsFrozenColumns: false, columnHeadersAsFrozenRows: false, includeAutoMergedCells: false, includeCalcModelCache: false, saveR1C1Formula: false, includeUnusedNames: true, includeEmptyRegionCells: true, losslessEditing: true, encoding: "UTF-8", rowDelimiter: "\r\n", columnDelimiter: ",", sheetIndex: 0, row: 0, column: 0, rowCount: 200, columnCount: 20, }; const openOptionsConfig = { sjs: [{ propName: "openMode", type: "select", displayText: "OpenMode", options: [{ name: 'normal', value: 0 }, { name: 'lazy', value: 1 }, { name: 'incremental', value: 2 }], default: 0 }, { propName: "includeStyles", type: "boolean", default: true }, { propName: "includeFormulas", type: "boolean", default: true }, { propName: "fullRecalc", type: "boolean", default: false }, { propName: "dynamicReferences", type: "boolean", default: true }, { propName: "incrementalCalculation", type: "boolean", default: false }, { propName: "includeUnusedStyles", type: "boolean", default: true }, ], xlsx: [{ propName: "openMode", type: "select", displayText: "OpenMode", options: [{ name: 'normal', value: 0 }, { name: 'lazy', value: 1 }, { name: 'incremental', value: 2 }], default: 0 }, { propName: "includeStyles", type: "boolean", default: true }, { propName: "includeFormulas", type: "boolean", default: true }, { propName: "frozenColumnsAsRowHeaders", type: "boolean", default: false }, { propName: "frozenRowsAsColumnHeaders", type: "boolean", default: false }, { propName: "fullRecalc", type: "boolean", default: false }, { propName: "dynamicReferences", type: "boolean", default: true }, { propName: "incrementalCalculation", type: "boolean", default: false }, { propName: "includeUnusedStyles", type: "boolean", default: true }, { propName: "convertSheetTableToDataTable", type: "boolean", default: false }], ssjson: [{ propName: "includeStyles", type: "boolean", default: true }, { propName: "includeFormulas", type: "boolean", default: true }, { propName: "frozenColumnsAsRowHeaders", type: "boolean", default: false }, { propName: "frozenRowsAsColumnHeaders", type: "boolean", default: false }, { propName: "fullRecalc", type: "boolean", default: false }, { propName: "incrementalLoading", type: "boolean", default: false }], csv: [{ propName: "encoding", type: "string", default: "UTF-8" }, { propName: "rowDelimiter", type: "string", default: "\r\n" }, { propName: "columnDelimiter", type: "string", default: "," }] }; const saveOptionsConfig = { sjs: [{ propName: "includeBindingSource", type: "boolean", default: false }, { propName: "includeStyles", type: "boolean", default: true }, { propName: "includeFormulas", type: "boolean", default: true }, { propName: "saveAsView", type: "boolean", default: false }, { propName: "includeAutoMergedCells", type: "boolean", default: false }, { propName: "includeCalcModelCache", type: "boolean", default: false }, { propName: "saveR1C1Formula", type: "boolean", default: false }, { propName: "includeUnusedNames", type: "boolean", default: true }, { propName: "includeEmptyRegionCells", type: "boolean", default: true }, ], xlsx: [{ propName: "includeBindingSource", type: "boolean", default: false }, { propName: "includeStyles", type: "boolean", default: true }, { propName: "includeFormulas", type: "boolean", default: true }, { propName: "saveAsView", type: "boolean", default: false }, { propName: "rowHeadersAsFrozenColumns", type: "boolean", default: false }, { propName: "columnHeadersAsFrozenRows", type: "boolean", default: false }, { propName: "includeAutoMergedCells", type: "boolean", default: false }, { propName: "includeUnusedNames", type: "boolean", default: true }, { propName: "includeEmptyRegionCells", type: "boolean", default: true }, { propName: "losslessEditing", type: "boolean", default: true }, ], ssjson: [{ propName: "includeBindingSource", type: "boolean", default: false }, { propName: "includeStyles", type: "boolean", default: true }, { propName: "includeFormulas", type: "boolean", default: true }, { propName: "saveAsView", type: "boolean", default: false }, { propName: "rowHeadersAsFrozenColumns", type: "boolean", default: false }, { propName: "columnHeadersAsFrozenRows", type: "boolean", default: false }, { propName: "includeAutoMergedCells", type: "boolean", default: false }, ], csv: [{ propName: "encoding", type: "string", default: "UTF-8" }, { propName: "rowDelimiter", type: "string", default: "\r\n" }, { propName: "columnDelimiter", type: "string", default: "," }, { propName: "sheetIndex", type: "number", default: 0 }, { propName: "row", type: "number", default: 0 }, { propName: "column", type: "number", default: 0 }, { propName: "rowCount", type: "number", default: 200 }, { propName: "columnCount", type: "number", default: 20 }, ] }; const spreadRef = ref(null); const selectedFile = ref(null); const openFileType = ref(''); const saveFileType = ref('sjs'); const excelFileType = ref('XLSX'); const initSpread = function (spread) { spreadRef.value = spread; let statusBar = new GC.Spread.Sheets.StatusBar.StatusBar(document.getElementById('statusBar')); statusBar.bind(toRaw(spread)); } const selectedFileChange = function (e) { selectedFile.value = e.target.files[0]; openFileType.value = getFileType(selectedFile.value); } const open = function () { let spread = toRaw(spreadRef.value); let file = selectedFile.value; if (!file) { return; } let fileType = getFileType(file); let options = getOptions('open'); if (fileType === 'sjs') { spread.open(file, function () {}, function () {}, options); } else { spread.import(file, function () {}, function () {}, options); } } const save = function () { let spread = toRaw(spreadRef.value); let fileType = saveFileType.value; let fileName = 'export.' + (fileType==='xlsx' ? excelFileType.value.toLowerCase() : fileType); let options = getOptions('save'); if (fileType === 'sjs') { spread.save(function (blob) { saveAs(blob, fileName); }, function () {}, options); } else { if (fileType === 'csv') { var { sheetIndex, row, rowCount, column, columnCount } = options; options.range = { sheetIndex: sheetIndex, row: row, rowCount: rowCount, column: column, columnCount: columnCount, }; } options.fileType = mapExportFileType(fileType); spread.export(function (blob) { saveAs(blob, fileName); }, function () {}, options); } } const getOptions = function (mode) { let optionsConfig, optionsValue; if (mode === 'open') { optionsConfig = openOptionsConfig[openFileType.value]; optionsValue = openOptions; } else { optionsConfig = saveOptionsConfig[saveFileType.value]; optionsValue = saveOptions; } let options = {}; optionsConfig.forEach((prop) => { let v = optionsValue[prop.propName]; if (prop.type === 'number') { v = +v; } options[prop.propName] = v; }); if (mode === 'save' && saveFileType.value === 'xlsx') { options['excelFileType'] = excelFileType.value; } return options; } const getFileType = function (file) { if (!file) { return; } let fileName = file.name; let extensionName = fileName.substring(fileName.lastIndexOf(".") + 1); if (extensionName === 'sjs') { return 'sjs'; } else if (extensionName === 'xlsx' || extensionName === 'xlsm' || extensionName === 'xltm' || extensionName === 'xltx') { return 'xlsx'; } else if (extensionName === 'ssjson' || extensionName === 'json') { return 'ssjson'; } else if (extensionName === 'csv') { return 'csv'; } } const mapExportFileType = function (fileType) { if (fileType === 'ssjson') { return GC.Spread.Sheets.FileType.ssjson; } else if (fileType === 'csv') { return GC.Spread.Sheets.FileType.csv; } return GC.Spread.Sheets.FileType.excel; } const needShow = function (mode, propName) { let options = mode === 'open' ? openOptionsConfig[openFileType.value] : saveOptionsConfig[saveFileType.value]; return options && options.find((p) => p.propName === propName); } const formatOptionLabel = function (text) { return text .replace(/([a-z])([A-Z])/g, '$1 $2') .replace(/([0-9])([A-Z][a-z])/g, '$1 $2') .replace(/\b[a-z]/g, function (letter) { return letter.toUpperCase(); }); } const showExcelFileType = () => saveFileType.value === 'xlsx'; </script> <style> html, body { height: 100%; margin: 0; } body { position: absolute; inset: 0; color: #1f2933; background: #f7f8fa; } #app { height: 100%; } </style> <style scoped> .sample-tutorial { display: flex; height: 100%; overflow: hidden; } .sample-container { display: flex; flex: 1 1 auto; flex-direction: column; min-width: 0; height: 100%; } .sample-spreadsheets { flex: 1 1 auto; min-height: 0; overflow: hidden; } #statusBar { flex: 0 0 25px; width: 100%; } .options-container { flex: 0 0 320px; width: 320px; height: 100%; padding: 18px 16px; box-sizing: border-box; overflow: auto; overflow-x: hidden; background: #ffffff; border-left: 1px solid #e5e7eb; } .sample-options { z-index: 1000; } .panel-header { padding-bottom: 14px; border-bottom: 1px solid #eef0f3; } .panel-header h1 { margin: 0; font-size: 18px; font-weight: 650; line-height: 1.25; } .panel-description { margin: 8px 0 0; color: #6b7280; font-size: 13px; line-height: 1.6; } .option-row { display: grid; } .inputContainer { box-sizing: border-box; } .control-section { padding: 14px 0; border-bottom: 1px solid #eef0f3; } .control-section:last-child { border-bottom: 0; } .control-section h2 { margin: 0 0 10px; color: #374151; font-size: 13px; font-weight: 700; line-height: 1.3; } .options-container label { color: #374151; font-size: 13px; font-weight: 600; line-height: 1.35; } .options-container select, .options-container input[type="text"], .options-container input[type="number"] { width: 100%; height: 30px; padding: 0 8px; box-sizing: border-box; color: #111827; font: inherit; background: #ffffff; border: 1px solid #d8dde5; border-radius: 6px; outline: none; transition: border-color .15s ease, box-shadow .15s ease; } .options-container select:focus, .options-container input[type="text"]:focus, .options-container input[type="number"]:focus, .options-container input[type="file"]:focus, .options-container button:focus { border-color: #2563eb; box-shadow: 0 0 0 3px rgba(37, 99, 235, .12); } .options-container input[type="file"] { display: block; min-width: 0; color: #374151; font-size: 12px; } .options-container input[type="file"]::file-selector-button { height: 28px; margin-right: 8px; padding: 0 10px; color: #1f4f82; font: inherit; font-weight: 600; cursor: pointer; background: #ffffff; border: 1px solid #9bb2cf; border-radius: 4px; } .options-container button, .options-container input[type="button"] { min-height: 30px; padding: 0 12px; box-sizing: border-box; color: #1f4f82; font: inherit; font-weight: 600; cursor: pointer; background: #ffffff; border: 1px solid #9bb2cf; border-radius: 4px; transition: background-color .15s ease, border-color .15s ease; } .options-container button:hover, .options-container input[type="button"]:hover { background: #edf5ff; border-color: #6f98c8; } .settingButton { flex: 0 0 auto; margin: 0; } .file-action-row, .save-action-row { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: 8px; align-items: center; min-width: 0; } .file-action-row { margin-bottom: 8px; } .file-action-row label, .save-action-row label { white-space: nowrap; } .file-action-row input[type="file"] { width: 100%; max-width: 100%; min-width: 0; overflow: hidden; text-overflow: clip; } .save-action-row { margin-bottom: 10px; } .save-action-row select { width: 100%; min-width: 0; } #open, #save { min-width: 56px; } .open-options .item, .save-options .item { display: flex; gap: 8px; align-items: center; min-height: 24px; margin: 4px 0; } .open-options .item label, .save-options .item label { flex: 1 1 auto; min-width: 0; font-weight: 500; overflow-wrap: anywhere; } .open-options .item select, .save-options .item select, .open-options .item input[type="text"], .save-options .item input[type="text"], .open-options .item input[type="number"], .save-options .item input[type="number"] { flex: 0 0 128px; width: 128px; height: 28px; } .open-options .item input[type="checkbox"], .save-options .item input[type="checkbox"] { width: 16px; height: 16px; margin: 0; accent-color: #2563eb; flex: 0 0 auto; } .excelFileTypeContainer { margin-bottom: 10px; } #saveExcelFileType { margin: 8px 0 0; } @media (max-width: 760px) { .sample-tutorial { flex-direction: column; } .sample-container { flex: 1 1 55%; min-height: 55%; } .options-container { flex: 0 0 45%; width: 100%; height: 45%; border-top: 1px solid #e5e7eb; border-left: 0; } } </style>
<!DOCTYPE html> <html style="height:100%;font-size:14px;"> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <title>SpreadJS VUE</title> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" type="text/css" href="$DEMOROOT$/en/vue3/node_modules/@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css"> <script src="$DEMOROOT$/spread/source/js/FileSaver.js" type="text/javascript"></script> <script src="$DEMOROOT$/en/vue3/node_modules/systemjs/dist/system.src.js"></script> <script src="./systemjs.config.js"></script> <script src="./compiler.js" type="module"></script> <script> var System = SystemJS; System.import("./src/app.js"); System.import('$DEMOROOT$/en/lib/vue3/license.js'); </script> </head> <body> <div id="app"></div> </body> </html>
(function (global) { SystemJS.config({ transpiler: 'plugin-babel', babelOptions: { es2015: true }, paths: { // paths serve as alias 'npm:': 'node_modules/', 'cdn:': 'https://cdn.mescius.io/demoapps/packages/spreadjs/19.2.0-master-2026-08-10-0936/' }, packageConfigPaths: [ './node_modules/*/package.json', "./node_modules/@mescius/*/package.json", "./node_modules/@babel/*/package.json", "./node_modules/@vue/*/package.json" ], map: { 'vue': "npm:vue/dist/vue.esm-browser.js", 'tiny-emitter': 'npm:tiny-emitter/index.js', 'plugin-babel': 'npm:systemjs-plugin-babel/plugin-babel.js', "systemjs-babel-build": "npm:systemjs-plugin-babel/systemjs-babel-browser.js", '@mescius/spread-sheets': 'cdn:@mescius/spread-sheets/index.js', '@mescius/spread-sheets-print': 'cdn:@mescius/spread-sheets-print/index.js', '@mescius/spread-sheets-vue': 'cdn:@mescius/spread-sheets-vue/index.js', '@mescius/spread-sheets-io': 'cdn:@mescius/spread-sheets-io/index.js', '@mescius/spread-sheets-charts': 'cdn:@mescius/spread-sheets-charts/index.js', '@mescius/spread-sheets-shapes': 'cdn:@mescius/spread-sheets-shapes/index.js', '@mescius/spread-sheets-slicers': 'cdn:@mescius/spread-sheets-slicers/index.js', '@mescius/spread-sheets-pivot-addon': 'cdn:@mescius/spread-sheets-pivot-addon/index.js', '@mescius/spread-sheets-reportsheet-addon': 'cdn:@mescius/spread-sheets-reportsheet-addon/index.js', '@mescius/spread-sheets-tablesheet': 'cdn:@mescius/spread-sheets-tablesheet/index.js', '@mescius/spread-sheets-ganttsheet': 'cdn:@mescius/spread-sheets-ganttsheet/index.js', }, meta: { '*.css': { loader: 'systemjs-plugin-css' }, '*.vue': { loader: "../plugin-vue/index.js" } } }); })(this);