Full spreadsheet editor with formulas, cell styling, multi-sheet support, charts, conditional formatting, named ranges, sorting, filtering, freeze panes, clipboard operations, find/replace, and import/export to XLSX/CSV/ODS/PDF.
<iframe id="ss-demo" src="/online/webapp/spreadsheet" width="100%" height="600" frameborder="0" style="border:1px solid #ccc; border-radius:4px;"></iframe>
<script>window._wsConnect('ss-demo', 'ssSocket');</script>
<iframe src="https://sgapps.io/online/webapp/spreadsheet"
width="100%" height="600" frameborder="0"></iframe>var csvUrl = "https://example.com/data.csv";
var src = "https://sgapps.io/online/webapp/spreadsheet/url/" + btoa(csvUrl);The editor supports three pre-configured embedding modes (set via the mode constructor option). The wrapping window currently launches in editor mode by default but the same instance can be queried via getMode:
| Mode | Toolbar | Formula Bar | Sheet Tabs | Editing | Best For |
|---|---|---|---|---|---|
"editor" | shown | shown | shown | enabled | Full spreadsheet application |
"viewer" | hidden | hidden | shown | disabled | Displaying data, reports, dashboards |
"minimal" | hidden | shown | hidden | enabled | Compact data-entry forms, embedded grids |
socket.fire("webapp::instance::request", "getMode",
function (err, mode) { console.log("Mode:", mode); });setValue -- Set Cell Valuesocket.fire("webapp::instance::request", "setValue", "A1", "Hello World",
function (err) { console.log(err || "Set"); });<button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','setValue','A1','Sales Data',function(){window.ssSocket.fire('webapp::instance::request','setValue','A2','100',function(){window.ssSocket.fire('webapp::instance::request','setValue','A3','250',function(){window.ssSocket.fire('webapp::instance::request','setValue','B1','Region',function(){window.ssSocket.fire('webapp::instance::request','setValue','B2','North',function(){window.ssSocket.fire('webapp::instance::request','setValue','B3','South')})})})})})">Try: Fill Sample Data</button>
setFormula -- Set Cell FormulaThe formula expression is without the leading = (the editor stores the raw expression). If you'd rather use the = prefix, just call setValue -- it auto-detects values starting with = as formulas.
// Direct formula (no leading =)
socket.fire("webapp::instance::request", "setFormula", "A4", "SUM(A2:A3)",
function (err) { console.log(err || "Formula set"); });
// Or via setValue with = prefix
socket.fire("webapp::instance::request", "setValue", "A4", "=SUM(A2:A3)");<button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','setFormula','A4','SUM(A2:A3)')">Try: Set SUM Formula in A4</button>
getFormula -- Get Cell Formulasocket.fire("webapp::instance::request", "getFormula", "A4",
function (err, expr) { console.log("Formula:", expr); });<button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','getFormula','A4',function(e,f){alert('A4 formula: '+(f||'(none)'))})">Try: Get A4 Formula</button>
setCellStyle -- Style a Cellsocket.fire("webapp::instance::request", "setCellStyle", "A1", {
bold: true, fontSize: 14, bg: "#4a6cf7", color: "#ffffff"
});The style object uses these properties (any subset is allowed):
| Property | Type | Default | Description |
|---|---|---|---|
bold | boolean | false | Bold text |
italic | boolean | false | Italic text |
underline | boolean | false | Underlined text |
strikethrough | boolean | false | Strikethrough text |
fontFamily | string | "Arial" | Font family name |
fontSize | number | 11 | Font size in points |
color | string | "#000000" | Text color (hex) |
bg | string | null | Background / fill color (hex). null = no fill |
align | string | "left" | Horizontal: "left", "center", "right" |
valign | string | "bottom" | Vertical: "top", "middle", "bottom" |
wrap | boolean | false | Wrap text within cell |
numFmt | string | "General" | Number format string (see below) |
borderTop / borderRight / borderBottom / borderLeft | Object | null | {style, width, color} -- style is "solid", "dashed", or "dotted" |
// Style a header row with bold blue background and a thick bottom border
socket.fire("webapp::instance::request", "setCellStyle", "A1:F1", {
bold: true,
bg: "#1a73e8",
color: "#ffffff",
align: "center",
fontSize: 12,
borderBottom: { style: "solid", width: 2, color: "#0d47a1" }
});<button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','setCellStyle','A1',{bold:true,fontSize:14,bg:'#4a6cf7',color:'#ffffff'})">Try: Style A1 (bold, blue bg)</button><button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','setCellStyle','A1:F1',{bold:true,bg:'#1a73e8',color:'#ffffff',align:'center',fontSize:12})">Try: Style header row A1:F1</button>
numFmt)The numFmt property controls how a cell value is displayed. Common format strings:
| Format | Example | Description |
|---|---|---|
"General" | 1234.5 | Default — no special formatting |
"0" | 1235 | Integer (rounded) |
"0.00" | 1234.50 | Fixed 2 decimal places |
"#,##0" | 1,235 | Thousands separator |
"#,##0.00" | 1,234.50 | Thousands + 2 decimals |
"$#,##0.00" | $1,234.50 | US currency |
"0%" | 12% | Percentage (value × 100) |
"0.00%" | 12.35% | Percentage with decimals |
"0.00E+0" | 1.23E+3 | Scientific notation |
"yyyy-mm-dd" | 2026-04-04 | ISO date |
"mm/dd/yyyy" | 04/04/2026 | US date |
"hh:MM:ss" | 14:30:00 | Time |
"@" | (text) | Text — no number conversion |
socket.fire("webapp::instance::request", "setCellStyle", "B2:B100", { numFmt: "$#,##0.00" }); // Currency
socket.fire("webapp::instance::request", "setCellStyle", "C2:C100", { numFmt: "0.0%" }); // Percentage
socket.fire("webapp::instance::request", "setCellStyle", "D2:D100", { numFmt: "yyyy-mm-dd" }); // DategetValue -- Get Cell Valuesocket.fire("webapp::instance::request", "getValue", "A1",
function (err, cell) { console.log("Value:", cell); });<button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','getValue','A1',function(e,c){alert('A1 value: '+JSON.stringify(c))})">Try: Get A1 Value</button>
// Add a new sheet
socket.fire("webapp::instance::request", "addSheet", "Data", function (err) {});
// Switch to sheet (0-based)
socket.fire("webapp::instance::request", "activeSheet", 1, function (err) {});
// Read current active sheet
socket.fire("webapp::instance::request", "activeSheet",
function (err, idx) { console.log("Active:", idx); });
// Rename sheet
socket.fire("webapp::instance::request", "renameSheet", 0, "Summary", function (err) {});
// Delete sheet
socket.fire("webapp::instance::request", "deleteSheet", 1, function (err) {});<button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','addSheet','Sheet 2')">Try: Add Sheet</button><button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','renameSheet',0,'Summary')">Try: Rename First Sheet</button><button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','activeSheet',function(e,i){alert('Active sheet idx: '+i)})">Try: Get Active Sheet</button>
// Insert 2 rows starting at row index 5
socket.fire("webapp::instance::request", "insertRow", 5, 2, function (err) {});
// Insert a column at column 0 (leftmost)
socket.fire("webapp::instance::request", "insertCol", 0, 1, function (err) {});
// Delete 3 rows starting at index 10
socket.fire("webapp::instance::request", "deleteRow", 10, 3, function (err) {});
// Delete a single column
socket.fire("webapp::instance::request", "deleteCol", 4, function (err) {});<button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','insertRow',1,1)">Try: Insert Row at index 1</button><button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','insertCol',1,1)">Try: Insert Column at index 1</button>
// Select a single cell
socket.fire("webapp::instance::request", "setSelection", "B2");
// Select a range
socket.fire("webapp::instance::request", "setSelection", "A1:D10");
// Read current selection
socket.fire("webapp::instance::request", "getSelection",
function (err, sel) {
console.log(sel.rangeStr); // e.g. "A1:D10"
console.log(sel.activeCell);
});<button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','setSelection','A1:C5')">Try: Select A1:C5</button><button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','getSelection',function(e,s){alert('Selection: '+JSON.stringify(s,null,2))})">Try: Get Selection</button>
// Sort range A1:D100 by column 0 ascending, then by column 2 descending
socket.fire("webapp::instance::request", "sort", "A1:D100",
[{col: 0, ascending: true}, {col: 2, ascending: false}],
function (err) {});
// Toggle auto-filter for current selection
socket.fire("webapp::instance::request", "filter", function (err) {});
// Find all matches
socket.fire("webapp::instance::request", "find", "Total",
{ matchCase: false, wholeCell: false, regex: false },
function (err, matches) {
// matches: [{ ref: "A2", sheet: 0, value: "Total" }, ...]
console.log("Found", matches.length, "matches");
});
// Find with a regex (treats query as a regular expression)
socket.fire("webapp::instance::request", "find", "\\d{4}-\\d{2}-\\d{2}",
{ regex: true });
// Replace
socket.fire("webapp::instance::request", "replace", "old", "new", { matchCase: true },
function (err, count) { console.log("Replaced", count); });| Option | Type | Default | Description |
|---|---|---|---|
matchCase | boolean | false | Case-sensitive search |
wholeCell | boolean | false | Match entire cell content (not substring) |
regex | boolean | false | Treat the query as a regular expression |
sheet | number | all | Search only in a specific sheet index |
// Copy current selection
socket.fire("webapp::instance::request", "copy");
// Or specify a range
socket.fire("webapp::instance::request", "copy", "A1:B5");
// Cut
socket.fire("webapp::instance::request", "cut", "A1:B5");
// Paste at active cell
socket.fire("webapp::instance::request", "paste");
// Paste mode: "all" | "values" | "formats" | "formulas" | "transpose"
socket.fire("webapp::instance::request", "paste", "D1", "values");
// Copy from one place to another in one call
socket.fire("webapp::instance::request", "copyRange", "A1:B5", "D1");<button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','copy','A1:B5')">Try: Copy A1:B5</button><button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','paste','D1','all')">Try: Paste at D1</button><button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','copyRange','A1:B5','F1')">Try: Copy A1:B5 → F1</button>
// Merge cells
socket.fire("webapp::instance::request", "merge", "A1:C1");
// Unmerge
socket.fire("webapp::instance::request", "unmerge", "A1:C1");
// Freeze first row + first 2 columns
socket.fire("webapp::instance::request", "freeze", 1, 2);
// Unfreeze
socket.fire("webapp::instance::request", "freeze", 0, 0);<button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','merge','A1:C1')">Try: Merge A1:C1</button><button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','unmerge','A1:C1')">Try: Unmerge A1:C1</button><button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','freeze',1,1)">Try: Freeze Row 1 + Col A</button><button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','freeze',0,0)">Try: Unfreeze</button>
Charts render as inline SVG and can be dragged/resized after insertion. Supported chart types: "bar", "line", "pie", "area", "scatter", "combo".
// Bar chart
socket.fire("webapp::instance::request", "insertChart", "A1:B7", "bar",
{ title: "Sales by Region", legend: "right", width: 400, height: 300 });
// Line chart
socket.fire("webapp::instance::request", "insertChart", "A1:C12", "line",
{ title: "Monthly Trend" });
// Pie chart
socket.fire("webapp::instance::request", "insertChart", "A1:B5", "pie",
{ title: "Market Share" });
// Scatter
socket.fire("webapp::instance::request", "insertChart", "A1:B50", "scatter",
{ title: "Correlation" });
// Area
socket.fire("webapp::instance::request", "insertChart", "A1:D12", "area",
{ title: "Revenue Breakdown" });<button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','insertChart','A1:F4','bar',{title:'Sample Chart'})">Try: Insert Bar Chart</button><button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','insertChart','A1:B5','pie',{title:'Sample Pie'})">Try: Insert Pie Chart</button>
Define names for cells or ranges to use them in formulas:
// Define
socket.fire("webapp::instance::request", "namedRange", "tax_rate", "B1");
socket.fire("webapp::instance::request", "namedRange", "prices", "Sheet1!B2:B100");
// Use in a formula
socket.fire("webapp::instance::request", "setValue", "C2", "=B2*tax_rate");
socket.fire("webapp::instance::request", "setValue", "D1", "=SUM(prices)");
// Read a named range
socket.fire("webapp::instance::request", "namedRange", "tax_rate",
function (err, ref) { console.log(ref); });Apply visual rules to highlight cells based on their values. Each rule is an object with a type discriminator.
// Highlight values greater than 1000 in red
socket.fire("webapp::instance::request", "conditionalFormat", "B2:B100", {
type: "cellIs",
operator: "greaterThan",
values: [1000],
style: { bg: "#fce4ec", color: "#c62828" }
});
// 3-color scale (green -> yellow -> red)
socket.fire("webapp::instance::request", "conditionalFormat", "C2:C100", {
type: "colorScale",
colors: ["#4caf50", "#ffeb3b", "#f44336"]
});
// Data bars
socket.fire("webapp::instance::request", "conditionalFormat", "D2:D50", {
type: "dataBar",
color: "#2196f3"
});
// Icon sets: 'arrows3', 'traffic3', 'stars3', 'flags3'
socket.fire("webapp::instance::request", "conditionalFormat", "E2:E50", {
type: "iconSet",
icons: "arrows3"
});
// Formula-based rule (alternate row shading)
socket.fire("webapp::instance::request", "conditionalFormat", "A2:F100", {
type: "expression",
formula: "=MOD(ROW(),2)=0",
style: { bg: "#f5f5f5" }
});"cellIs", "colorScale", "dataBar", "iconSet", "expression"cellIs):* "greaterThan", "lessThan", "equal", "notEqual", "greaterThanOrEqual", "lessThanOrEqual", "between", "notBetween"// Export as CSV (active sheet)
socket.fire("webapp::instance::request", "exportCSV",
function (err, csv) { console.log(csv); });
// Export sheet by index
socket.fire("webapp::instance::request", "exportCSV", 0,
function (err, csv) { console.log(csv); });
// Export as XLSX (Promise -> Blob)
socket.fire("webapp::instance::request", "exportXLSX",
function (err, blob) {
var url = URL.createObjectURL(blob);
// download or display
});
// Export as ODS / PDF
socket.fire("webapp::instance::request", "exportODS", function (err, blob) {});
socket.fire("webapp::instance::request", "exportPDF", function (err, blob) {});
// Full state as JSON
socket.fire("webapp::instance::request", "toJSON",
function (err, data) { console.log(data); });
// Restore state from JSON
socket.fire("webapp::instance::request", "fromJSON", savedData);
// Import a file (XLSX, CSV, ODS, ...)
var file = /* a File or Blob */;
socket.fire("webapp::instance::request", "importFile", file,
function (err) { if (!err) console.log("Imported"); });<button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','exportCSV',function(e,csv){alert('CSV:\n\n'+(csv||'empty'))})">Try: Export CSV</button><button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','toJSON',function(e,d){alert('JSON keys: '+Object.keys(d||{}).join(', '))})">Try: Export JSON</button><button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','exportXLSX',function(e,b){alert('XLSX blob size: '+(b&&b.size||0)+' bytes')})">Try: Export XLSX (Blob)</button>
toJSON returns -- and fromJSON accepts -- this workbook structure. You can save it to localStorage / IndexedDB / a server, then restore it later in any spreadsheet instance:
{
"name": "Workbook",
"sheets": [
{
"name": "Sheet1",
"tabColor": null,
"rows": { "5": { "height": 30, "hidden": false } },
"cols": { "2": { "width": 150, "hidden": false } },
"cells": {
"A1": { "v": "Revenue", "s": { "bold": true, "bg": "#4a6cf7", "color": "#fff" } },
"B1": { "v": 50000, "f": null, "s": { "numFmt": "$#,##0" } },
"B2": { "v": null, "f": "B1*1.1", "s": {} }
},
"merges": ["A1:C1"],
"freeze": { "row": 1, "col": 0 },
"filters": null,
"charts": [],
"conditionalFormats": [],
"namedRanges": { "total": "B10" },
"validations": []
}
],
"activeSheet": 0
}v = raw value, f = formula expression (without =, or null), s = style object (see Cell Styles).Tip: the engine recalculates all formulas when you callfromJSON, so cells withv: null, f: "..."are filled in automatically. You don't need to persist computed values.
// Save to localStorage on every cell change
socket.on("api-event::instance:event:cell-change", function () {
socket.fire("webapp::instance::request", "toJSON", function (err, data) {
if (!err) localStorage.setItem("myWorkbook", JSON.stringify(data));
});
});
// Restore on page load
var saved = localStorage.getItem("myWorkbook");
if (saved) {
socket.fire("webapp::instance::request", "fromJSON", JSON.parse(saved));
}socket.fire("webapp::instance::request", "zoom", 1.5); // 150%
socket.fire("webapp::instance::request", "readOnly", true); // read-only mode
socket.fire("webapp::instance::request", "freeze", 1, 1); // freeze first row + col
socket.fire("webapp::instance::request", "print"); // open print dialog<button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','zoom',1.25)">Try: Zoom 125%</button><button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','zoom',1)">Try: Zoom 100%</button><button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','undo')">Try: Undo</button><button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','redo')">Try: Redo</button><button onclick="window._ws('ssSocket')&&window.ssSocket.fire('webapp::instance::request','print')">Try: Print</button>
The Spreadsheet ships with 9 dialogs that can be opened remotely. Each one is a fully interactive form -- the user fills it in and the changes are applied automatically.
socket.fire("webapp::instance::request", "showFormatCellsDialog");
socket.fire("webapp::instance::request", "showSortDialog");
socket.fire("webapp::instance::request", "showFindDialog", true); // true = find/replace
socket.fire("webapp::instance::request", "showConditionalFormatDialog");
socket.fire("webapp::instance::request", "showDataValidationDialog");
socket.fire("webapp::instance::request", "showNamedRangeDialog");
socket.fire("webapp::instance::request", "showChartDialog");
socket.fire("webapp::instance::request", "showFunctionWizard");
socket.fire("webapp::instance::request", "showPrintDialog");| Dialog | Description |
|---|---|
Format Cells (Ctrl+1) | 5 tabs: Number, Alignment, Font, Border, Fill |
| Sort | Multi-level sort with column/direction selectors |
Find & Replace (Ctrl+F/Ctrl+H) | Search with match case, whole cell, regex options |
| Conditional Format | Rule builder: cell value, formula, color scale, data bar, icon set |
| Data Validation | 3 tabs: Settings (type/operator/values), Input Message, Error Alert |
| Named Range Manager | List, add, edit, delete named ranges |
| Insert Chart | Chart type grid with preview, title/legend settings |
| Function Wizard | Category filter, function list, argument builder (also reachable from the fx button in the formula bar) |
Print (Ctrl+P) | Print area, orientation, margins, scale, headers/footers |
Inside the Data Validation dialog (or for users embedding the editor and calling validation programmatically through their own code) the rule shape is:
// Dropdown list
{ type: "list", list: ["High", "Medium", "Low"], message: "Select a priority" }
// Number range
{ type: "number", operator: "between", value1: 0, value2: 100, message: "0 to 100" }
// Date range
{ type: "date", operator: "greaterThan", value1: "2026-01-01" }
// Text length
{ type: "textLength", operator: "lessThanOrEqual", value1: 50 }
// Custom formula
{ type: "custom", formula: "=AND(F2>=0, MOD(F2,1)=0)", message: "Positive integer" }"list", "number", "date", "textLength", "custom""between", "notBetween", "equal", "notEqual", "greaterThan", "lessThan", "greaterThanOrEqual", "lessThanOrEqual"The Spreadsheet forwards internal events to the embedder via api-event::instance:<eventName>. The first element of the args array is the event payload.
| Event | Payload | Description |
|---|---|---|
event:ready | -- | Spreadsheet fully initialized and rendered |
event:cell-change | {ref, oldValue, newValue, sheet} | A cell value or formula was modified |
event:recalculate | -- | Formulas were recalculated |
event:sheet-change | {index, name} | The active sheet was switched (or a sheet was added/deleted/renamed) |
event:selection-change | {start: {row, col}, end: {row, col}, sheet} | Selection range changed |
Editor-only events: the underlying library also emitsevent:before-edit,event:after-edit,event:context-menu,event:scroll,event:zoom,event:importandevent:export. These are not currently forwarded by the wrapper but can be added on request.
// Cell value or formula changed
socket.on("api-event::instance:event:cell-change", function (args) {
var data = args[0];
console.log("Cell " + data.ref + " : " + data.oldValue + " -> " + data.newValue);
});
// Recalculation finished
socket.on("api-event::instance:event:recalculate", function () {
console.log("Formulas recalculated");
});
// Sheet added/deleted/renamed
socket.on("api-event::instance:event:sheet-change", function (args) {
var s = args[0];
console.log("Active sheet:", s.index, s.name);
});
// Selection moved
socket.on("api-event::instance:event:selection-change", function (args) {
var sel = args[0];
console.log("From", sel.start, "to", sel.end);
});
// Editor finished initial load
socket.on("api-event::instance:event:ready", function () {
console.log("Spreadsheet ready");
});Whenever the spreadsheet has focus, the following keyboard shortcuts are available:
| Shortcut | Action |
|---|---|
Enter | Confirm edit, move down |
Tab / Shift+Tab | Confirm edit, move right / left |
Escape | Cancel edit |
F2 | Enter edit mode on selected cell |
Delete | Clear cell content |
Ctrl+Z | Undo |
Ctrl+Y / Ctrl+Shift+Z | Redo |
Ctrl+C / Ctrl+X / Ctrl+V | Copy / Cut / Paste |
Ctrl+D | Fill down |
Ctrl+R | Fill right |
Ctrl+B / Ctrl+I / Ctrl+U | Bold / Italic / Underline |
Ctrl+A | Select all cells |
Ctrl+F | Open Find dialog |
Ctrl+H | Open Find & Replace dialog |
Ctrl+G | Go to cell dialog |
Ctrl+Home / Ctrl+End | Navigate to A1 / last used cell |
Ctrl+; / Ctrl+Shift+; | Insert current date / time |
Ctrl+1 | Open Format Cells dialog |
Ctrl+Shift+L | Toggle auto-filter |
Arrow keys | Move selection |
Ctrl+Arrow | Jump to edge of data region |
Shift+Arrow | Extend selection |
Shift+Click / Ctrl+Click | Extend selection / multi-selection |
Page Up / Page Down | Scroll by one page |
Ctrl+P | Print current sheet |
Alt+Enter | Insert new line inside a cell |
The formula engine supports 200+ functions. Use them with setValue (with leading =) or setFormula (without leading =):
socket.fire("webapp::instance::request", "setValue", "D2", "=B2*C2");
socket.fire("webapp::instance::request", "setValue", "D10", "=SUM(D2:D9)");
socket.fire("webapp::instance::request", "setValue", "E2", '=IF(D2>1000,"High","Low")');
socket.fire("webapp::instance::request", "setValue", "F2", "=VLOOKUP(A2,Sheet2!A:B,2,FALSE)");
socket.fire("webapp::instance::request", "setValue", "G2", '=TEXT(B2,"$#,##0.00")');
socket.fire("webapp::instance::request", "setValue", "H2", '=IFERROR(B2/C2,"N/A")');SUM, AVERAGE, MIN, MAX, COUNT, COUNTA, ROUND, CEILING, FLOOR, POWER, SQRT, MOD, RAND, RANDBETWEEN, PI, LOG, LN, EXP, INT, SIGN, TRUNC, PRODUCT, SUMPRODUCT, SIN, COS, TAN, ASIN, ACOS, ATAN, ATAN2, DEGREES, RADIANS, ABSSUMIF, SUMIFS, COUNTIF, COUNTIFS, AVERAGEIF, AVERAGEIFSCONCAT, CONCATENATE, LEFT, RIGHT, MID, LEN, UPPER, LOWER, PROPER, TRIM, SUBSTITUTE, REPLACE, FIND, SEARCH, TEXT, VALUE, REPT, CHAR, CODE, EXACT, T, TEXTJOINIF, AND, OR, NOT, XOR, IFERROR, IFNA, IFS, SWITCH, TRUE, FALSEVLOOKUP, HLOOKUP, INDEX, MATCH, OFFSET, INDIRECT, ROW, COLUMN, ROWS, COLUMNS, ADDRESS, CHOOSENOW, TODAY, DATE, YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, DATEVALUE, DAYS, EDATE, EOMONTH, WEEKDAY, WEEKNUMMEDIAN, MODE, STDEV, VAR, LARGE, SMALL, RANK, PERCENTILE, QUARTILE, CORREL, FORECASTPMT, FV, PV, NPV, IRR, NPERISBLANK, ISERROR, ISNUMBER, ISTEXT, ISLOGICAL, ISNA, TYPE, NA, ERROR.TYPE| Error | Meaning |
|---|---|
#REF! | Invalid cell reference |
#VALUE! | Wrong value type |
#DIV/0! | Division by zero |
#NAME? | Unrecognized function or name |
#N/A | Value not available |
#NULL! | Invalid range intersection |
#NUM! | Invalid numeric value |
#CIRC! | Circular reference detected |
<iframe id="sheet" src="https://sgapps.io/online/webapp/spreadsheet"
width="100%" height="500" frameborder="0"></iframe>
<script src="https://sgapps.io/components/application-prototype/ApplicationPrototype.js"></script>
<script src="https://sgapps.io/components/window-socket/index.js"></script>
<script>
var socket = new WindowSocket();
socket.start();
socket.on("webapp::connection::ping", function () {
socket.fire("webapp::instance::embed-mode", true);
// Listen for changes
socket.on("api-event::instance:event:cell-change", function (args) {
console.log("Cell changed:", args[0]);
});
// Fill a data table
var data = [
["Product", "Q1", "Q2", "Q3", "Q4"],
["Widget A", 120, 150, 180, 200],
["Widget B", 80, 95, 110, 130],
["Widget C", 200, 220, 250, 280]
];
data.forEach(function (row, r) {
row.forEach(function (val, c) {
var ref = String.fromCharCode(65 + c) + (r + 1);
socket.fire("webapp::instance::request", "setValue", ref, String(val));
});
});
// Add SUM formulas (no leading "=" with setFormula)
socket.fire("webapp::instance::request", "setFormula", "F2", "SUM(B2:E2)");
socket.fire("webapp::instance::request", "setFormula", "F3", "SUM(B3:E3)");
socket.fire("webapp::instance::request", "setFormula", "F4", "SUM(B4:E4)");
socket.fire("webapp::instance::request", "setValue", "F1", "Total");
// Style header row
["A1","B1","C1","D1","E1","F1"].forEach(function (ref) {
socket.fire("webapp::instance::request", "setCellStyle", ref, {
bold: true, bg: "#4a6cf7", color: "#fff", align: "center"
});
});
// Freeze the header row
socket.fire("webapp::instance::request", "freeze", 1, 0);
// Apply a number format to data cells
["B2","C2","D2","E2","F2","B3","C3","D3","E3","F3","B4","C4","D4","E4","F4"].forEach(function (ref) {
socket.fire("webapp::instance::request", "setCellStyle", ref, { numFmt: "#,##0" });
});
});
</script>