DocumentationUpgrades
What's New in Version 13
Overview
Version 13 introduces a new sparse storage engine and a modular architecture. Memory and processing now scale with the data a worksheet actually contains, not with the size of the grid — a worksheet with 500,000 mostly empty rows costs a fraction of what it did in version 12.
This release also rebuilds the undo and redo system for real-time collaboration: history records track rows, columns and worksheets by identity, so undo applies to the correct cells even after structural changes made locally or by other connected users. The legacy property methods accumulated over several versions were unified into one organized API.
Highlights
- Sparse Storage: Cell records are created on demand and organized in pages; blank areas of the grid cost nothing
- Modular Architecture: The monolithic core was split into ES modules
- Collaboration-Aware Undo: History follows rows, columns and worksheets by identity — undo lands on the right cells after inserts, deletes, moves or changes made by other users
- Collaboration is version 13 only: a version 13 document must be opened by version 13 clients on every peer. The style palette, the identity guids carried by the delete methods and the new property and nested header methods are replayed as they are, and a version 12 client would not understand them. Keep version 12 clients on version 12 documents
- Lazy Borders: Border elements are only materialized inside the viewport
- Organized Properties API: One consistent, batch-first API for cell, column and row properties
New features
- Properties API:
setCellProperties, setColumnProperties and setRowProperties with their getters, batch signatures and the events onchangecellproperties, onchangecolumnproperties and onchangerowproperties
- Row and column identity: a
guid on every row and column, managed automatically and synchronized between connected users
- Column and row styles:
setStyle({ 'A:C': ... }) stores one entry on the column itself; covered cells inherit it
- Structural awareness: tables, media anchors and range filters follow inserts, deletes and moves of rows and columns, with exact undo
- Multi column sorting:
orderBy([{ column, direction }, ...]) and Shift + double click to add sorting levels
- Fill shortcuts:
Ctrl+D and Ctrl+R with formulas and formatting in one undoable operation
- Nested header editing:
splitNestedCell, mergeNestedCell, moveNestedHeader, the boundary drag, the group drag and the context menu entries, with allowEditNestedHeaders to disable the interactive editing
- Select then grab: the header of a fully selected column, row or nested group is the drag handle, with a distinct colour, as in Google Sheets
- Nested header selection: Shift-click extends across groups, Ctrl-click adds a group, and a right-click keeps a multi-group selection
- Clipboard API:
pasteArea, getClipboard, isClipboardText, the paste options (values, numberFormat, transpose, formatOnly, ...) and formulas that follow a transposed paste
- Conditional rules and visual scales:
duplicate, unique, aboveAverage, belowAverage, top and bottom validations, the dataBar and colorScale actions and stopIfTrue on style rules
- Spilled range operator:
B2# references a spilled array and follows copy, fill and structural changes
- Excel intersection operator:
=B2:B4 A3:C3
- Row group outline levels: the Excel outline model with up to eight levels and the
groupIndentation option
- Raw data: the
raw argument on getData, getDataFromRange, getRowData, getColumnData and the range form of getValue
- Plugins: the
events map for per-event subscriptions, including the gated events
- Accessibility: the ARIA grid model (
gridcell, aria-rowindex, aria-colindex, aria-rowcount, aria-colcount, aria-sort, aria-selected)
- Helpers:
helpers.transformTokenWithF4 and helpers.verifyWorksheetName; getCellRowObject(y) for direct access to the sparse row records; getDependents(cell) and getPrecedents(cell) to read the dependency graph of the engine
- Events:
onchangezoom and onbeforemoveworksheet
Behavior and Critical Updates
- Persistence payloads carry the original method input. Transformations (casting, formulas, events) are repeated by every peer that replays the operation; transformed values never travel
- Undo after delete and restore: undoing a change on a row or column that was deleted and later restored (by undo, local or remote) now applies correctly; when the target no longer exists, the change is skipped instead of writing to the wrong cell
- Row and column identity: row and column definitions may carry a
guid property, managed automatically and preserved across insert, delete, undo and collaboration messages
- Paste replaces destination merges. The pasted content replaces everything in the target area, merges included; only the merges the content carries are re-created. Version 12 kept the destination merge and dropped the values landing on its covered cells (see Clipboard)
Upgrade Requirements
Version 13 keeps the best compatibility possible with version 12, with one significant exception: the legacy property methods were replaced by a new API. Review the changes below before upgrading.
Dependencies
The dependencies of version 12 remain valid: version 13 runs with Formula Pro 6 and jSuites 6, so no dependency upgrade is required.
<script src="https://cdn.jsdelivr.net/npm/@jspreadsheet/formula-pro@6/dist/index.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jsuites@6/dist/index.min.js"></script>
Potential Breaking Changes
Properties API
The legacy methods mixed cell and column targets in a single overloaded signature. Version 13 replaces them with three explicit method pairs. All setters take an array, so batch operations are native.
| Status |
Method |
Description |
| New |
setCellProperties(data) |
Batch cell properties; null resets to the column definitions |
| Updated |
setCellProperties bounds |
Invalid entries are skipped; all-invalid batches return false |
| Updated |
rotate(cell, angle) |
Validated, with history, persistence and headless support |
| New |
getCellProperties(x, y) |
Effective properties of a cell |
| New |
setColumnProperties(data) |
Batch column definitions; identity preserved |
| New |
getColumnProperties(x) |
The column definitions |
| New |
setRowProperties(data) |
Batch row definitions; identity preserved |
| New |
getRowProperties(y) |
The row definitions |
| Removed |
setProperty |
Use setCellProperties or setColumnProperties |
| Removed |
resetProperty |
Use setCellProperties with value: null |
| Removed |
getProperty |
Use getCellProperties or getColumnProperties |
| Removed |
getOptions |
Use getCellProperties |
| Removed |
setColumnOptions |
Use setColumnProperties |
| Removed |
getColumnOptions |
Use getColumnProperties |
Migrating the common calls:
// Version 12: cell target (x, y, options)
worksheet.setProperty(1, 4, { type: 'text' });
// Version 13
worksheet.setCellProperties([{ x: 1, y: 4, value: { type: 'text' } }]);
// Version 12: column target (x, options)
worksheet.setProperty(1, { type: 'checkbox' });
// Version 13
worksheet.setColumnProperties([{ column: 1, value: { type: 'checkbox' } }]);
// Version 13: rows now have the same capability
worksheet.setRowProperties([{ row: 3, value: { height: 40 } }]);
The new setters use replace semantics by default: the object passed becomes the new definitions. To change a subset of properties, add update: true to the record — only the given keys are applied over the current ones (and only the delta travels to other connected users):
worksheet.setCellProperties([{
x: 0,
y: 0,
value: { mask: '0.00' },
update: true,
}]);
Events
Every event addition and signature change in version 13; the full details
live in each feature section.
| Status |
Event |
Description |
| New |
onchangecellproperties |
(worksheet, records) after setCellProperties |
| New |
onchangecolumnproperties |
(worksheet, records) after setColumnProperties |
| New |
onchangerowproperties |
(worksheet, records) after setRowProperties |
| New |
onchangezoom |
(worksheet, newValue, oldValue) after the zoom changes |
| New |
onbeforemoveworksheet |
(worksheet, from, to); false cancels |
| Updated |
onresize |
Now (worksheet, width, height) |
| Updated |
onchangeconfig |
Now (worksheet, config, spreadsheetLevel) |
| Updated |
onbeforeformula |
A returned string replaces the expression |
| Updated |
Gated events for plugins |
Plugins subscribed through events receive them |
| Removed |
onchangeproperty |
Replaced by the three property events above |
Each properties records entry carries value (the new properties) and oldValue (the previous ones).
New Methods
A quick reference of every method added in version 13; the details live in
each feature section.
| Status |
Method |
Description |
| New |
setCellProperties(data) |
Batch cell properties (see Properties API) |
| New |
getCellProperties(x, y) |
Effective properties of a cell (see Properties API) |
| New |
setColumnProperties(data) |
Batch column definitions (see Properties API) |
| New |
getColumnProperties(x) |
The column definitions (see Properties API) |
| New |
setRowProperties(data) |
Batch row definitions (see Properties API) |
| New |
getRowProperties(y) |
The row definitions (see Properties API) |
| New |
getCellRowObject(y) |
Direct access to the sparse row records |
| New |
getDependents(cell) |
Formulas that read a cell, as cell names |
| New |
getPrecedents(cell) |
References a formula reads |
| New |
splitNestedCell(x, y) |
Splits a nested header group at column x |
| New |
mergeNestedCell(x, y, to?) |
Merges nested header groups; the inverse of a split |
| New |
moveNestedHeader(x, y, d) |
Moves a nested header group with its columns |
| New |
orderBy(levels) |
Multi column sort: [{ column, direction }, ...] |
| New |
getData(..., raw) |
Sixth argument returns computed values without formatting |
| New |
helpers.transformTokenWithF4(token) |
Cycles a reference through the absolute forms |
| New |
helpers.verifyWorksheetName(name) |
Quotes a worksheet name for a reference |
| New |
pasteArea(area, destination, cut, source) |
Pastes an area into another position without a copy |
| New |
getClipboard() |
Origin of the last copy or cut |
| New |
isClipboardText(text) |
Whether the clipboard still holds that copy |
New Options
| Status |
Option |
Description |
| New |
allowEditNestedHeaders |
false disables interactive nested header editing |
| New |
guid |
Row and column identity, managed automatically |
| New |
groupIndentation |
Row group outline visuals; true or a pixel step |
| New |
zebra |
true bands the odd rows; toggle with setConfig |
Rows and Columns
| Status |
Item |
Description |
| Updated |
Structural performance |
Structural changes never walk the empty area of a sparse grid |
| Updated |
moveRow / moveColumn validation |
Out of range positions return false |
| Updated |
Delete validation |
A batch with any invalid position is refused |
| Updated |
Insert broadcasts |
Plain inserts no longer ship filler rows to peers |
| Updated |
Restored rows and columns |
Undoing a delete restores the complete row or column |
| Updated |
setMerge document hygiene |
Merging without borders writes no empty style entries |
| New |
Tables follow the structure |
Table ranges follow structural changes, with undo |
| New |
Media follows the structure |
Media anchors follow structural changes, with undo |
| New |
Filters follow the structure |
Range filters follow structural changes, with undo |
| Updated |
Filter controls cleanup |
Disabling a range filter removes its controls |
| Updated |
Table names |
Unique across the workbook |
| Updated |
Table header row |
headerRow (default false) decides whether the first row names the columns |
| Updated |
Groups and moves |
Moves into or out of a group resize it, with undo |
| Updated |
Column zebra |
Bands every cell of the column; colour is --jss-background-color-zebra |
| Status |
Item |
Description |
| New |
guid |
Row and column identity; never overwrite it |
| Updated |
deleteRow / deleteColumn |
Array form: the second argument carries the peer guids |
| Updated |
Collaboration peers |
Version 13 to version 13 only |
| New |
getCellRowObject(y) |
Direct access to the sparse row records |
Clipboard
- Notes and threaded comments belong to the cell and travel with it: a copy carries them to the destination, and a cut moves them, leaving none at the origin. Version 12 pasted the values and left the notes where they were
- The pasted content replaces everything in the destination area, merges included: a merge touching the target range is removed and only the merges the pasted content carries are re-created. In version 12 the destination merge survived and the values landing on its covered cells were silently dropped
- A merge travels only when the copied area holds it whole: a merge partially inside the area cannot move as one, so it is dropped instead of re-created shifted — and a cut still removes it from the origin
- Cut and paste follows the Excel move contract for formula references: a reference follows the cell it points at if, and only if, that cell moved along. This applies inside the moved formulas (
=B28+C28 moved with its C28 becomes =B28+D28) and to every formula in the workbook referencing the moved cells, on any worksheet, with $ markers preserved; a range reference follows when it moved as a whole. A move across worksheets requalifies both sides: the moved formula keeps pointing at the source cells (=A1*2 becomes ='Sheet1'!A1*2) and the formulas left behind follow the moved cells (=B1+5 becomes ='Sheet2'!D5+5). In version 12 every reference stayed as written, pointing at the old positions
- A paste is a single history entry: the value writes, the source clearing of a cut and the merge moves apply and revert as one transaction. Cutting a merged area and pasting it over its own source keeps the merged content, and one undo restores values, styles, cell configuration — the number format of the destination included — and merges at both ends. A paste made while
history.cascade is on joins the entry that is open, so a caller can group it with the operations around it
pasteArea(area, destination, cut, source) pastes an area of the worksheet (or of another one, through source) straight into a position [x, y] with the fidelity of an internal copy — values, styles, formats and merges travel, and cut clears the origin. No copy has to happen first and the clipboard stays untouched: whatever the user copied is still there to be pasted. The formulas follow the operation being performed: a copy shifts their references to the position they land on (=A1*2 copied one row down becomes =A2*2), while a cut applies the move contract above
getClipboard() returns the origin of the last copy or cut made inside the spreadsheet — { worksheet, selection, highlighted, cut, value } — or null when there is none, a destroyed spreadsheet included. The system clipboard carries text alone, so this is what a caller needs to paste on its own terms: only the number formats, transposed, or as a link to the source cells
isClipboardText(text) tells whether the text is still the one that copy produced, or whether another application has replaced it on the clipboard since. It is the question a paste answers for itself before rebuilding the cells, now available to a caller that reads the clipboard on its own — a menu that offers to paste a part of the copy, for instance, has to know before showing the options
- Both
paste and pasteArea take options for what of each cell travels, so a caller pastes a part of it instead of pasting everything and undoing the rest: values (the result of the formulas instead of the formulas), styles: false, properties: false (no cell configuration), numberFormat (of the configuration, only the mask), borders: false (the styles except the borders), transpose (rows become columns) and formatOnly (the looks alone — styles, configuration and merges — leaving every value and note of the destination as it is, and the origin of a cut untouched). The formats fill the selection they are pasted over, whatever its size: the copied pattern repeats and is cut at the edge, merges included, the way a format painter paints the range it is dragged over. pasteArea takes a rectangle, or a list of rectangles, as its destination and pastes over it by the rules of a paste over a selection: the block repeats over an exact multiple, the formats fill any size, and several rectangles are all or nothing. The valuesOnly, dataOnly and styleOnly of version 12 keep working and say the same in fewer words
- Formulas follow the transposition: each relative offset swaps its axes, so a reference to the neighbour on the left becomes a reference to the neighbour above, a whole column becomes a whole row (
=SUM(I:I) becomes =SUM(10:10)) and absolute references stay where they are
- A copy of multiple ranges (
Ctrl+click or Ctrl+drag on the selection) pastes the results of its formulas. The ranges land side by side at the destination, without the gap between them, so there is no single origin to shift the references by; version 12 pasted the formulas as written, still pointing at the original cells. Multiple ranges can be copied but not cut: a cut moves what it takes and the references follow the move, which more than one range cannot express, so the cut is refused with a notification
- A paste of the values (
Ctrl+Shift+V, "Paste values", the values and valuesOnly options) of cells spilled by an array formula carries the spilled results. Version 12 resolved only the cell holding the formula and pasted the spilled cells blank
Undo and Redo
History records reference the worksheet by id and rows/columns by identity instead of numeric coordinates alone:
- Undo and redo apply at the current position of the affected cells, even after rows or columns were inserted, deleted or moved — locally or by another connected user
- Undoing a change on a row or column that was deleted and later restored works across all connected users
- When the target genuinely no longer exists (deleted and not restored), the change is skipped — nothing is written to the wrong cell
- Every worksheet-scoped action (styles, widths, visibility, merges, comments, groups, sorting, and the rest) resolves its worksheet by id at undo time: undoing changes made before a worksheet was deleted and restored applies to the restored worksheet, never to the dead instance
- The identity contract covers values, formulas and formula reference rewrites, styles and style resets, comments, merges, row/column visibility, widths and heights, headers, groups (definitions and open/close state) and the filter range — every positional action. Undoing a column deletion that rewrote formula references restores the exact original formulas, with no stale
#REF! copies on the wrong cells
Persistence Protocol
If you implemented a custom persistence handler or server integration, note:
- Payloads contain the original, untransformed method input — every peer replays the method and repeats the transformations
- Internal working fields (
w, col, row, oldValue) never travel
deleteRow / deleteColumn broadcast the plain indexes with the identity guids aligned as the second argument — deleteRow(rows, guids) — so the replay signature stays the method signature
Zoom
| Status |
Item |
Description |
| Updated |
setZoom(z) |
Only positive finite numbers; anything else resets to 1 |
| New |
onchangezoom |
(worksheet, newValue, oldValue) after the zoom changes |
Zoom is a personal view preference: it is never persisted, synced to other users or recorded in the undo history. Use onchangezoom to save it locally (e.g. localStorage) if your application needs to restore it.
Worksheets
| Status |
Item |
Description |
| New |
onbeforemoveworksheet |
(worksheet, from, to); false cancels |
| Updated |
moveWorksheet(f, t) |
Invalid positions return false; the active worksheet stays |
| Updated |
renameWorksheet(index, name) |
Invalid names return false; case-only renames allowed |
| Updated |
deleteWorksheet(index) |
The last-worksheet guard runs before the event |
Viewport
| Status |
Item |
Description |
| Updated |
setViewport(w, h) |
Percentage strings are accepted and preserved |
| Updated |
onresize |
Now (worksheet, width, height) |
Serialization
| Status |
Item |
Description |
| Updated |
getConfig() |
Per-user view state no longer serializes |
| Updated |
Style serialization |
Column and row styles serialize as one entry |
Validations
| Status |
Item |
Description |
| Updated |
Sparse evaluation |
Validations no longer materialize cell records |
| Updated |
getValidations(index) |
Returns undefined without validations |
| Updated |
setValidations |
Unknown targets are ignored instead of throwing |
| Updated |
hasErrors() |
Scans only the validated ranges |
| Updated |
List sources |
Resolved once and cached; never serialized |
| New |
Conditional rules |
duplicate, unique, aboveAverage, belowAverage, top and bottom |
| New |
Visual scales |
dataBar and colorScale actions |
| New |
Stop if true |
Every matching rule applies; stopIfTrue cuts the rest |
| New |
Rule reordering |
The extension modal reorders rules and edits stop if true |
Defined Names, Groups and Media
| Status |
Item |
Description |
| Updated |
getDefinedNames(name) |
Returns undefined for unknown names |
| Updated |
setDefinedNames |
Invalid entries are skipped; false when nothing applies |
| Updated |
resetDefinedNames |
Accepts plain names as well as descriptors |
| Updated |
Defined names reload |
Serialized defined names reload correctly |
| Updated |
setRowGroup / setColumnGroup |
Invalid positions return false |
| Updated |
getMedia() |
No argument returns all media |
| Updated |
Serialization |
collapsed and element references never serialize |
| Updated |
onbeforeloadimage |
Fires only when the image source changes |
| New |
Row group outline levels |
jss_group_header and jss_group_level_1 to _8 classes; visuals via groupIndentation |
| Updated |
Nested group visibility |
Opening a parent never reveals a closed nested group |
Search, Pagination and Shortcuts
| Status |
Item |
Description |
| Updated |
page(n) |
Clamped to the last page; invalid input returns false |
| Updated |
whichPage(y) |
Returns null for rows outside the results |
| Updated |
search(term) |
Numeric terms accepted; faster on large worksheets |
| Updated |
jspreadsheet.shortcuts.set |
Multi-character keys resolve; custom shortcuts take precedence |
| Updated |
oncloserowgroup / onclosecolumngroup |
The correct close event fires |
Group open and close, search terms and the current page are personal view preferences: never persisted or synced to other users. Group open/close history entries are kept for compatibility with previous versions.
Plugins
The plugin system was reworked for performance: every handler is indexed once at registration, so the per-operation overhead no longer grows with the number of plugins.
Breaking: the array registration form was removed. setPlugins accepts only an object of plugin methods. If you registered plugins with the array form, migrate as follows:
// Version 12 (also worked): array of descriptors
spreadsheet.setPlugins([
{ name: 'myPlugin', plugin: myPlugin, options: {} },
]);
// Version 13: object form only
spreadsheet.setPlugins({ myPlugin });
The plugin itself is unchanged — a method that receives (spreadsheet, options, config) and returns the plugin instance. All existing hooks keep working: init, persistence, toolbar, contextMenu, onevent.
New: subscribe to specific events. Instead of receiving every event through the generic onevent funnel — including the per-cell rendering events — a plugin can declare an events map. Each handler is called only for its own event, with the same arguments as the equivalent config handler:
const myPlugin = function(spreadsheet, options, config) {
return {
events: {
// No event name argument and no switch needed
onchange: function(worksheet, cell, x, y, newValue) {
// ...
},
onselection: function(worksheet, x1, y1, x2, y2) {
// ...
},
},
// The generic funnel still works and can coexist with events
onevent: function(event) {
// ...
},
};
}
| Status |
Item |
Description |
| Removed |
Array registration |
Use the object form { name: method } |
| New |
events map |
Handlers fire only for their own event |
| Updated |
Gated events |
Reach plugins subscribed through events |
| Updated |
onevent |
Unchanged; indexed once at registration |
| Updated |
Hooks |
Indexed at registration; no cost per operation |
Data
| Status |
Item |
Description |
| New |
raw argument |
Computed values without formatting on the data getters |
| Updated |
CSV escaping |
The delimiter is a literal string, not a regex |
| Updated |
Processed values |
Resolved through the editor, never the DOM |
| Removed |
extended argument |
Editors implement get(options, value, instance) |
// A1 = 1234.5 with mask #,##0.00 ; B1 = =A1*2 with the same mask
worksheet.getData(); // [[1234.5, '=A1*2']] stored input
worksheet.getData(false, true); // [['1,234.50', '2,469.00']] formatted
worksheet.getData(false, true, null, null, null, true); // [[1234.5, 2469]] computed, unformatted
worksheet.getValue('A1:B1', true, true); // same view over a range
Formulas and History
| Status |
Item |
Description |
| Updated |
History |
Constant time per edit |
Configuration and Dimensions
| Status |
Item |
Description |
| Updated |
setConfig with minDimensions |
Grid growth applies on every environment |
| Updated |
setConfig partial updates |
Absent properties keep their state |
| Updated |
setWidth / setHeight |
Validate positions and respect editable |
| Updated |
getWidth(column) |
Returns undefined for a missing column |
| Updated |
Dimension validation |
Widths and heights must be positive numbers |
| Updated |
setConfig input |
Invalid input returns false |
| Updated |
onchangeconfig |
Now (worksheet, config, spreadsheetLevel) |
Events and Extensions
| Status |
Item |
Description |
| Updated |
Window focus |
Returning to the window restores keyboard navigation |
| Updated |
Touch double tap |
Resolves the cell element; formatted cells open the editor |
| Updated |
setExtensions |
Names conflicting with the core API are refused |
| Updated |
International decimal |
Resolved on every environment, including the server |
Formula Engine Integration
| Status |
Item |
Description |
| Updated |
onbeforeformula |
A returned string replaces the expression |
| Updated |
setFormula persistence |
Payload is { x, y, value, force } per record |
| Updated |
F4 reference cycling |
Sheet-qualified tokens cycle their reference part only |
| Updated |
Chain resolution errors |
Missing worksheets resolve to #REF! without console noise |
| Updated |
Escaped quotes in worksheet names |
='It''s'!A1 joins the dependency chain |
| Updated |
Apostrophes in worksheet names |
It's and Its are different worksheets; double the apostrophe in references |
| Updated |
Value reads on plain worksheets |
No spill lookup on worksheets without spills |
| Updated |
Spill arrays and redo |
Redo of a spill removal clears the members again |
| New |
Intersection operator |
A space between references is kept as the operator |
| New |
Spilled range operator |
B2# references the spilled array; chain and transforms follow |
Headers and Nested Headers
| Status |
Item |
Description |
| Updated |
Nested header definitions |
Normalized on load: {title} objects, colspan 1, align center |
| Updated |
Nested header titles |
Rendered as text |
| Updated |
setNestedHeaders / resetNestedHeaders |
Respect editable; one remote operation |
| Updated |
setNestedCell |
Invalid coordinates return false; batches skip them |
| Updated |
getNestedCell |
Returns null for a missing cell |
| Updated |
Nested render maps |
Cached per nested row |
| New |
splitNestedCell(x, y) |
Splits a group at column x; also in the context menu |
| New |
Nested boundary drag |
Drag a group boundary to move columns between groups |
| Updated |
Appended columns |
A column appended after the last group extends it |
| Updated |
Nested groups and frozen panes |
A frozen pane never splits a nested group |
| New |
mergeNestedCell(x, y, to?) |
Merges groups from x to to; also in the context menu |
| New |
moveNestedHeader(x, y, d) |
Moves a group with its columns inside its row |
| New |
Nested group drag |
Select a group, then drag it with its columns |
| New |
allowEditNestedHeaders |
false disables interactive nested header editing |
| Updated |
Column and row drag |
Select, then grab the header, as in Google Sheets |
| New |
Full selection handles |
Fully selected headers carry jss_full |
| Updated |
Nested header selection |
Shift and Ctrl modifiers work on nested groups |
| Updated |
onchangenested |
Fires after every nested header change, with the full definition |
| Updated |
insertRow / insertColumn |
The selection survives the insert |
| Updated |
Persistence of sub-steps |
Internal sub-steps no longer reach persistence |
New Shortcuts
| Status |
Shortcut |
Description |
| New |
Ctrl+D |
Fill down, with formulas and formatting |
| New |
Ctrl+R |
Fill right, with formulas and formatting |
| Updated |
Ctrl+Arrow |
Excel block navigation |
| Updated |
Ctrl+Shift+Arrow |
Extends the selection to the block target |
| Updated |
F4 (formula editor) |
Cycles the reference under the caret through the absolute forms |
Accessibility
| Status |
Item |
Description |
| Updated |
ARIA model |
gridcell, row, columnheader, rowheader, aria-sort and aria-selected |
Frozen Rows and Columns
| Status |
Item |
Description |
| Updated |
Freeze boundary over nested headers |
Snaps to the nearest group edge |
| Updated |
Freeze validation |
Invalid configurations are sanitized |
Navigation
| Status |
Item |
Description |
| Updated |
Ctrl+Arrow block navigation |
Lands on the last cell of a block, or the first value after a gap |
| Updated |
Ctrl+Arrow over merged cells |
A merge acts as one cell with the value of its anchor |
| Updated |
Entering a merge across the viewport |
Scrolls to the start of the merge |
| Updated |
Jump performance |
The empty tail resolves through the occupied bound |
| Updated |
Navigation on the server |
Navigation methods work headless |
Scroll and Selection
| Status |
Item |
Description |
| Updated |
Scroll performance |
Row offsets come from the cumulative height index |
| Updated |
Selection on the server |
Selection getters work on the server |
| Updated |
Multiple spreadsheets on a page |
Only the instance holding the selection reports it |
| Updated |
Locked cells |
Explicitly unlocked cells are selectable |
| Updated |
Fill on the server |
The fill handle refuses on the server |
Context Menu
| Status |
Item |
Description |
| Updated |
Nested header context menu |
Restored |
Formula Editor (Picker)
| Status |
Item |
Description |
| Updated |
Caret positioning |
Uses document.createRange(); no throw on empty |
| New |
multiple picker option |
Picks several areas in one session |
Sorting
| Status |
Item |
Description |
| New |
Multi column sort |
orderBy([{ column, direction }, ...]) |
| New |
Shift + double click |
Adds the column as the next sorting level |
| Updated |
onbeforesort / onsort |
Fifth argument: the applied levels |
| Updated |
Sorting large columns |
Coerced once per row; much faster |
| Updated |
Sorting with an active search |
Recomputed from the stored term; works on the server |
| Updated |
orderBy validation |
Out of range column returns false |
Toolbar and Spreadsheet Instance
| Status |
Item |
Description |
| Breaking |
Toolbar methods moved |
getToolbar, setToolbar, showToolbar, hideToolbar and refreshToolbar live on the spreadsheet only: spreadsheet.showToolbar() (from a worksheet: worksheets[0].parent.showToolbar()). The toolbar belongs to the spreadsheet, so the worksheet-level copies were removed |
| Updated |
Multiple instances |
Per-instance resources are scoped |
| Updated |
setToolbar(items) |
Releases the previous toolbar and its pickers |
| Updated |
Toolbar merge button |
Works on never materialized cells |
| Updated |
jspreadsheet.destroyAll() |
Also destroys namespaced spreadsheets |
| Updated |
CommonJS interop |
require() returns the jspreadsheet object itself |
| Updated |
notification(message) |
Callable; routes through onerror |
Styles
| Status |
Item |
Description |
| New |
Column and row styles |
setStyle({ 'A:C': ... }) stores one entry per column or row |
| Updated |
getStyle(cell) |
Resolves own, options, column or row style in every environment |
| Updated |
Copy, paste and fill |
Carries the inherited style to the target |
| Updated |
Stylesheet updates |
CSS rebuilds only for new styles |
| Updated |
Undo precision |
Undo restores the inheritance |
| Updated |
Style precedence |
Own, options, column, then row |
| Updated |
Headless styles |
Fully functional without a DOM |
Meta and Cache
| Status |
Item |
Description |
| Updated |
setMeta values |
Zero and false are stored as given |
| Updated |
setMeta / setCache validation |
Invalid entries return false; batches skip them |