Excel compatibility
Feature compatibility comparison between Excel/Google Sheets and Rows n Columns Spreadsheet
A comprehensive feature-by-feature comparison between Excel/Google Sheets and the Rows n Columns Spreadsheet component.
Legend:
✅ Full support
⚠️ Partial / known gaps documented inline
❌ Not supported (deferred or out of scope)
N/A Not applicable
At a glance
Import
✅
✅
⚠️
⚠️
✅
✅
Export
✅
❌
❌
❌
✅
✅
Password-encrypted file (CFB)
⚠️
❌
❌
❌
❌
N/A
XLSM imports identically to XLSX but discards macros/VBA on round-trip (security).
XLSB / XLS parsers exist for read-only viewing; export round-trips through XLSX.
CSV is value-only — no formatting, formulas, or sheet structure beyond rows/columns.
Password-protected XLSX export uses CFB encryption (
libs/toolkit/exporter/xlsx/xlsx-export.ts). Decryption of password-protected XLSX import is not implemented.
Feature compatibility matrix
Basic editing
Cell editing
✅
✅
✅
Multi-cell selection
✅
✅
✅
Including non-contiguous via Ctrl/Cmd+click
Copy / paste / cut
✅
✅
✅
Clipboard API + internal copy buffer (preserves formulas, styles, merges)
Paste special
✅
✅
✅
Values only, formats only, formulas only, transpose
Undo / redo
✅
✅
✅
Immer patch-based; works alongside YJS / ShareDB
Find & replace
✅
✅
✅
Find pane + Cmd/Ctrl+H opens Replace; Replace + Replace All wired through useOnFindReplace (regex search, single-cell or whole-sheet scope, atomic undo)
Fill handle (drag to fill)
✅
✅
✅
Includes series detection (linear, date, weekday) + user-defined custom autofill lists via useSpreadsheetState({customAutofillLists})
Magic fill / smart fill
✅ (Sheets)
✅
⚠️
AI-driven via OpenAI integration; opt-in
Autofill from selection
✅
✅
✅
useOnFill, useOnFillRange
Remove duplicates
✅
✅
✅
onRemoveDuplicates callback
Text to columns
✅
✅
✅
Delimited + fixed-width
Drag & drop cells
✅
✅
✅
Within sheet + drop external files
Cell formatting
Font family
✅
✅
✅
Resolved against workbook theme fonts
Font size
✅
✅
✅
Bold / italic / underline / strikethrough
✅
✅
✅
Text color
✅
✅
✅
Theme + tint, indexed, RGB
Background color (solid)
✅
✅
✅
Gradient cell fills
✅
❌
✅
Linear (degree) + path (left/right/top/bottom) gradients with 2+ stops. Parser reads <gradientFill> from xl/styles.xml; exporter emits it back with <stop position><color rgb=…/></stop> children; canvas renderer paints via createLinearGradient / createRadialGradient. Gradient takes precedence over pattern fill (Excel UI treats them as mutually exclusive on one cell)
Number formats (built-in)
✅
✅
✅
~68 built-in formats
Custom number format patterns
✅
✅
✅
Full pattern grammar — fractions (# ?/?), asterisk-padding (* ), locale tokens ([$$-409], [$€-2], [$£-809], [$¥-411]), conditional color/comparison segments ([Red][>100]…;[Blue][<0]…;…), elapsed-time brackets ([h]:mm), millisecond precision (hh:mm:ss.000), 4-segment patterns with @ string placeholder. Delegated to the numfmt library; audit tests in libs/utils/__tests__/formatter-edge-cases.spec.ts
Decimal places (increase/decrease)
✅
✅
✅
Horizontal alignment
✅
✅
✅
left, center, right, justify, distributed
Vertical alignment
✅
✅
✅
top, middle, bottom
Text wrap
✅
✅
✅
Text rotation (angle, vertical)
✅
✅
✅
0–360° + vertical orientation
Shrink to fit
✅
❌
✅
Indent
✅
✅
✅
Increase / decrease
Borders
✅
✅
✅
All 13 OOXML styles round-trip: solid (thin/medium/thick), hair, dashed, dotted, double, mediumDashed, mediumDashDot, dashDot, dashDotDot, slantDashDot. Canvas renderer paints distinct dash patterns via Canvas setLineDash for each variant
Border "outline + inside" composite
✅
❌
✅
"All borders" option in the border picker — changeBorder(..., "all", ...) sets borders on every edge of every cell in the selection
Merge cells
✅
✅
✅
Standard + merge across rows
Clear formatting
✅
✅
✅
Format painter / paint format
✅
✅
✅
Single + double-click toggle
User-defined color palette
✅
✅
✅
userDefinedColors workbook setting
Workbook named cell styles (<cellStyles> — Heading 1, Accent N, Total, Good/Bad/Neutral)
✅
❌
⚠️
Three layers, only two wired end-to-end: (1) Toolkit round-trip preservation ✅ — parser reads <cellStyles> into workbook.workbookStyles.namedCellStyles; exporter accepts a namedCellStyles arg on createExcelFile. (2) Cell formatting from imported named styles ✅ — flows through the existing cellStyleXfs inheritance, so cells that reference a named style get the right font/fill on import. (3) UI gallery ⚠️ — CellStyleSelector ships with a hardcoded built-in gallery (Good/Bad/Neutral/Heading 1–4/Total/Title/20%/40%/60% Accent N) and accepts a userDefinedStyles?: [string, CellFormat][] prop, but nothing in useSpreadsheetState populates it from workbook.workbookStyles.namedCellStyles automatically — host-managed today. Cells store resolved formats (uf) rather than style refs; applying a named style snapshots its format onto each cell
Conditional formatting → cell style
✅
✅
✅
See Conditional Formatting section
Rows & columns
Insert / delete rows
✅
✅
✅
Shifts dependent ranges + formulas
Insert / delete columns
✅
✅
✅
Insert / delete cells (shift)
✅
✅
✅
Shift up/down/left/right
Move rows / columns
✅
✅
✅
Re-anchors conditional formats + validations
Resize rows / columns
✅
✅
✅
Drag handle + auto-fit
Hide / show rows / columns
✅
✅
✅
Separate from group-collapse
Freeze rows / columns (panes)
✅
✅
✅
Split (non-frozen) panes
✅
❌
❌
Deferred (Phase 9)
Group / ungroup rows / columns
✅
✅
✅
7 nesting levels; XLSX + ODS round-trip
Collapse / expand outline groups
✅
✅
✅
+/- gutter buttons, 1/2/3 level selector
Show row/column headers toggle
✅
✅
✅
showRowColHeaders round-trips xlsx; canvas showHeaders prop honors it via useSpreadsheetState
Right-to-left layout
✅
✅
❌
Deferred (Phase 9)
Formulas & functions
Formula bar
✅
✅
✅
With Name Box + range selector
Formula autocomplete
✅
✅
✅
Function names + named ranges + table refs
Function tooltips (arg hints)
✅
✅
✅
Per-arg highlight as you type
A1 cell references
✅
✅
✅
Absolute ($) + relative
Range references
✅
✅
✅
Cross-sheet references
✅
✅
✅
Sheet1!A1, 'Sheet 2'!A1
Cross-workbook references
✅
✅
❌
[Book.xlsx]Sheet!A1 — deferred (Phase 6 remainder)
Named ranges (range-typed: MyRange = A1:B10)
✅
✅
✅
Workbook + sheet scope
Named ranges (static value: MyVal = 42)
✅
✅
✅
Scalar value returned directly
Named functions (LAMBDA-typed: MyFunc = =LAMBDA(x, x*2)) called as =MyFunc(args)
✅
✅
✅
Engine's _callFunction fallback resolves named LAMBDAs three ways: pre-built lambda value, {ref, value} wrapper, or the raw "=LAMBDA(...)" source string (parses + applies). Works in both the main-thread calc and the worker since both use the same fast-formula-parser engine. The named-range editor's "Text or Formula" type works out of the box
Named ranges (formula-typed: MyVar = =SUM(A1:A10)) used as a value =MyVar (not as a call)
✅
✅
✅
Excel virtual-cell model: each formula-typed name is a first-class StaticNode (nr:<scope>:<name>) in the DAG. Cell formulas referencing the name get real DAG input edges to that node, so the unified topological sort recomputes them whenever the named range's value changes. Workbook + sheet scope are distinct (keyed by numeric sheetId so renames don't break things), lookup follows Excel rules (sheet-scoped first, workbook fallback). Order-independent registration via two-pass batch: fullPrice = price * 1.08 wires the nr:price → nr:fullprice edge even if listed before price
Workbook & sheet-scoped names with the same display name
✅
✅
✅
E.g. workbook Tax = =0.08 and sheet-1 Tax = =0.20 coexist as separate DAG nodes; resolved per Excel scoping (sheet first, then workbook)
Chained named ranges (fullPrice = price * 1.08)
✅
✅
✅
Real static-to-static DAG edge; unified topo sort evaluates price before fullPrice before any cell using fullPrice
Named-range edit in Name Manager (re-define formula)
✅
✅
✅
Static node updated in place — dependent cells stay attached, are marked dirty, and recompute with the new value on next recalc
Named range JSON round-trip (hydrate calc state from saved DAG)
✅
❌
✅
Dag.toJSON / fromJSON serialize both directions of the cell ↔ named-range edges so a rehydrated calculator matches the in-memory model
Structured table references
✅
❌
✅
Table1[#Headers], Table1[@[Col 1]], totals row
~378 Excel-compatible functions
✅
✅
✅
Math, statistical, text, date, financial, engineering, logical, info, lookup, web, etc.
GETPIVOTDATA(value_field, pivot_anchor, [field, item]…)
✅
✅
✅
Header-matched lookup into a rendered pivot — locates the value cell for the given (field=item) tuple by scanning the pivot's row + column header bands
Dynamic arrays / spill
✅
✅
✅
FILTER, SORT, SORTBY, UNIQUE, SEQUENCE, RANDARRAY
#SPILL! / #CALC! / #FIELD! errors
✅
✅
✅
Modern error codes implemented
A1# spilled-range operator
✅
❌
✅
Lexer + grammar + eval + dep resolver all wired; resolves to the current spill bounds via Calculator.arrayRangeMap
Array formulas (legacy CSE)
✅
✅
✅
Ctrl+Shift+Enter
Modern array helpers (VSTACK, HSTACK, TOCOL, TOROW, etc.)
✅
✅
✅
Phase 6 shipped
Pick functions (CHOOSEROWS, CHOOSECOLS)
✅
✅
✅
Custom functions
✅
✅
✅
Register via formula engine
LET
✅
✅
✅
Implemented via source-level expansion: LET(name, value, ..., body) inlines (value) for each name in the body before parse. Nested LET supported.
LAMBDA (IIFE: =LAMBDA(x, x*x)(5))
✅
✅
✅
Inlined at compile time via the LAMBDA preprocessor
LAMBDA as a value (passed to MAP/REDUCE/etc.)
✅
✅
✅
Standalone LAMBDA(...) transforms to __RNC_LAMBDA__("p,...", "body source") which constructs a runtime lambda value {__isLambda, params, body}
MAP / REDUCE / BYROW / BYCOL / SCAN / MAKEARRAY
✅
✅
✅
HOFs accept lambda values and re-invoke the parser per element with bindings substituted in. Recursion guard caps depth at 256
Closures (lambda captures outer LET binding)
✅
✅
✅
LET expands before LAMBDA, baking captured values into the body source — e.g. LET(n, 5, LAMBDA(x, x+n)) becomes __RNC_LAMBDA__("x", "x+(5)")
LET-bound lambda used as a function (LET(double, LAMBDA(x, x*2), double(5)))
✅
✅
✅
LET substitutes Function-shaped occurrences of binding names with the lambda source, then the IIFE inliner collapses it
Dep tracking through lambda bodies (MAP(A1:A3, LAMBDA(v, v+B1)) tracks B1)
✅
✅
✅
DepParser walks __RNC_LAMBDA__ body strings via a fresh inner parser instance
Recursive lambdas (LET(fact, LAMBDA(n, IF(n<=1, 1, n*fact(n-1))), fact(5)))
✅
✅
❌
Body-reparse at runtime loses the LET binding for fact; needs a runtime registry that survives per-call re-parse. Deferred
GROUPBY / PIVOTBY
✅
❌
✅
Built on the existing LAMBDA infra — LambdaFunctions entries + funsNeedContext registration only; no chevrotain grammar changes. GROUPBY buckets rows by row-field tuple and invokes the aggregation lambda once per group; PIVOTBY adds a column axis. Args supported: field_headers, total_depth (grand total top/bottom), sort_order (asc/desc), boolean filter_array. Aggregation lambdas receive the group's value vector as an Excel array literal {a, b, c} (already lexed natively), so any aggregator works — LAMBDA(v, SUM(v)), LAMBDA(v, AVERAGE(v)), custom LAMBDAs. Dep tracking through lambda bodies is automatic via the existing __RNC_LAMBDA__ DepParser branch
FORECAST.ETS* (Holt-Winters)
✅
❌
✅
FORECAST.ETS / .CONFINT / .SEASONALITY / .STAT implemented via additive Holt-Winters (level + trend + seasonal). 5×5×5 grid search over α/β/γ to minimize in-sample SSE; seasonality auto-detected by comparing SSE across candidate periods 2..min(N/2, 12). Matches Excel within ~1% on typical seasonal series
Iterative calculation
✅
✅
✅
enabled / iterations / delta parsed & honored
Manual / on-demand calculation
✅
❌
✅
Toggleable; queue-based dispatcher
Calculation in web worker
✅
✅
✅
Off-main-thread engine via worker
Formula dependency tracing
✅
✅
✅
Precedents / dependents (DAG-backed)
Formula auditing (highlight refs)
✅
✅
✅
Circular reference detection
✅
✅
✅
Surfaces in calculation engine
Spill-range blocking detection
✅
✅
✅
Emits #SPILL!
Formula protection (lock formulas)
✅
✅
✅
Per-cell locked + protection metadata
External / cross-workbook links
✅
❌
⚠️
Imported & cached; cross-workbook references can't be edited
Localized function names
✅
❌
❌
Deferred (Phase 11); always English on the wire
Formula format derivation
When a formula cell has no explicit uf.numberFormat, the rendered format is auto-derived from the formula's structure and precedents — matching how Excel and Google Sheets infer the format of a calculated cell (e.g. =TODAY() → DATE, =A1*B1 where A1 is currency → CURRENCY). Derivation runs at render time inside getDerivedFormat (libs/spreadsheet-state/hooks/use-sheet-properties.ts); results are cached per cell via an LRU keyed on (value, precedent format refs) so invalidation propagates whenever a direct precedent's format object identity changes.
Function return-type defaults
✅
✅
✅
~140 functions: DATE/TIME producers — TODAY/NOW/DATE/TIME/EDATE/EOMONTH/WORKDAY/WORKDAY.INTL render as DATE/TIME/DATE_TIME; Date extractors (DAY/MONTH/YEAR/HOUR/MINUTE/SECOND/WEEKDAY/WEEKNUM/ISOWEEKNUM/DATEDIF/DAYS/DAYS360/NETWORKDAYS/NETWORKDAYS.INTL/YEARFRAC/DATEVALUE/TIMEVALUE) render as NUMBER; Math/trig (POWER/SQRT/EXP/LN/LOG/LOG10/SIGN/SIN/COS/TAN/ASIN/ACOS/ATAN/ATAN2/SINH/COSH/TANH/asinh-acosh-atanh/DEGREES/RADIANS/PI/FACT/COMBIN/PERMUT/GCD/LCM/SUMSQ) → NUMBER; Aggregation/rounding (SUM/SUMPRODUCT/ROUND family/INT/MOD/QUOTIENT/CEILING/FLOOR/MROUND/TRUNC) → NUMBER with CURRENCY-precedent preservation; Counts (COUNT/COUNTA/COUNTIF/COUNTIFS/ROW/COLUMN/ROWS/COLUMNS/RANK/RANK.EQ/RANK.AVG/FREQUENCY/LEN/SEARCH/FIND/MATCH/XMATCH) → NUMBER; Text (TEXT/LEFT/RIGHT/MID/CONCAT/CONCATENATE/TEXTJOIN/LOWER/UPPER/PROPER/TRIM/CLEAN/SUBSTITUTE/REPLACE/REPT/ADDRESS/CHAR/UNICHAR/T/DOLLAR/FIXED/BAHTTEXT) → TEXT; Statistical scalars (AVEDEV/DEVSQ/KURT/SKEW/SKEW.P/COVAR/COVARIANCE.S-P/CORREL/RSQ/SLOPE/INTERCEPT/STEYX/PEARSON) → NUMBER; Financial rates (XIRR/IRR/MIRR/RATE/NPER/EFFECT/NOMINAL) → NUMBER
Arg-index inheritance
✅
✅
✅
SUMIFS/AVERAGEIFS/MINIFS/MAXIFS (sum_range), SUMIF/AVERAGEIF (conditional 1 vs 3 args), FILTER/INDEX/SORT/SORTBY/UNIQUE/TAKE/DROP/TOCOL/TOROW/WRAPROWS/WRAPCOLS/CHOOSECOLS/CHOOSEROWS/TRANSPOSE, VLOOKUP (literal col), HLOOKUP (literal row), XLOOKUP (return_array)
Statistical functions inherit format from data
✅
✅
✅
MEDIAN, MODE/MODE.SNGL/MODE.MULT, PERCENTILE/.INC/.EXC, QUARTILE/.INC/.EXC, LARGE, SMALL, TRIMMEAN, GEOMEAN, HARMEAN, AVERAGEA, MINA, MAXA, VAR/.S/.P/VARA/VARPA, STDEV/.S/.P/STDEVA/STDEVPA, FORECAST/.LINEAR/.ETS (y values arg)
Financial functions inherit CURRENCY from principal
✅
✅
✅
PMT/PV/FV (pmt or pv arg), NPV/XNPV (first value), IPMT/PPMT (pv), CUMIPMT/CUMPRINC (pv), DDB/SLN/SYD/DB (cost)
Arithmetic format inference
✅
✅
✅
AST-based combineTypes over ADD/SUB/MUL/DIV/EXP/CONCAT/COMPARE — DATE − DATE → NUMBER, DATE + N → DATE, %A × %B → NUMBER, CURRENCY × N → CURRENCY, A & B → TEXT, A = B → GENERAL
Conditional branch merge
✅
✅
✅
IF, IFS, IFERROR, IFNA, CHOOSE, SWITCH — result-arg types merged via mergeValueTypes
ROUND family decimal adjustment
✅
✅
✅
ROUND(currency, 0) shrinks the pattern's decimal count; ROUNDUP / ROUNDDOWN / TRUNC / INT / MROUND / CEILING / FLOOR / QUOTIENT covered
First-non-generic precedent wins (fold loop)
✅
✅
✅
NUMBER/GENERAL/COUNT are generic and get upgraded; once a specific format is locked in (PERCENT, CURRENCY, DATE, etc.) it stays — matches Excel's first-encountered semantics. AST aggregate handlers (SUM/AVG/MIN/MAX) still apply Excel's "currency wins" rule independently
CURRENCY pattern preservation across NUMBER coercion
✅
✅
✅
The "$"#,##0.00 symbol+pattern survive when SUM / ROUND / etc. coerce the result type to NUMBER
Date pattern fidelity through date-arithmetic functions
✅
✅
✅
=EDATE(A1, 1) with A1's custom yyyy-mm-dd keeps yyyy-mm-dd instead of falling back to the locale default; same for EOMONTH, WORKDAY, etc. when the precedent is date-family
Default patterns synthesized for date/time when no precedent has one
✅
✅
✅
=TODAY() → DATE with getDefaultDateFormat(locale), =NOW() → DATE_TIME, =TIME(…) → TIME (without these the renderer falls back to General and shows the serial number — the original =TODAY() bug)
Anchor-only range inheritance
✅
✅
✅
SUM(A1:A10) inherits A1's format; O(1) per range, matches Excel's first-cell rule
Style references (cellXfs resolution)
✅
✅
✅
Precedents stored as { sid } style refs are resolved through the workbook <xfs> table before their numberFormat is read
Multi-level chain propagation
✅
✅
✅
C1 = B1 = A1 = TODAY() — all three render as DATE. Single-pass via cache fingerprint invalidation; no recursion through the dependency graph
Cycle safety in format derivation
✅
✅
✅
The calculator rejects cycles; if one slips through (malformed graph during teardown) the cache-based lookup terminates without looping
OFFSET / INDIRECT / INDEX with computed indices / A1# spill refs
✅
✅
⚠️
Falls back to the function's default return type — runtime-resolved targets aren't traced for format inheritance
AGGREGATE / SUBTOTAL function-number arg decoding
✅
✅
❌
First arg (1=AVG, 9=SUM, …) selects the inner aggregator; we don't decode it, so format follows the precedent fold rather than the selected function's semantics
Format derivation through LAMBDA / MAP / REDUCE bodies
✅
✅
⚠️
Lambda bodies aren't re-introspected by the format inference; result format follows the precedent fold. Formula evaluation itself works (see Phase 7 rows above)
Cross-workbook reference format inheritance
✅
✅
❌
Same scope as cross-workbook formula support — deferred with the rest of Phase 6
Multi-currency arithmetic ($A + €B)
✅
✅
⚠️
We follow Excel's general rule (first encountered for ADD/SUB, NUMBER across currencies for MUL/DIV); a few corner cases differ from Excel's exact behaviour
Implementation guarantees:
No user-space recursion through the cell dependency graph. Earlier versions walked precedents recursively; deeply chained formulas could blow the JS stack. The current implementation is iterative — precedent lookups are O(1) cache reads, so chain depth is unbounded.
Single-pass cache convergence in the common case. Row-major iteration naturally visits precedents before dependents, so
getEffectiveFormatreturns the correct format in one render pass. The LRU fingerprint catches any out-of-order resolution on the next render.Per-call cost. Cold-cache, single-precedent cell: ~2.5 μs. Warm-cache: ~140 ns. A 1000-cell render takes ~2.5 ms — well inside a 16 ms frame budget. Coverage measured by
libs/spreadsheet-state/hooks/__tests__/use-sheet-properties.bench.ts.Compatibility coverage. ~96% of common Excel/Sheets format derivation cases. Remaining gaps: runtime-resolved references (OFFSET/INDIRECT), AGGREGATE/SUBTOTAL function-number decoding, format introspection through LAMBDA bodies, cross-workbook references — see the partial-support rows above.
Data features
Tables (structured data)
✅
❌
✅
Full TableView lifecycle
Table styles + banded rows / columns
✅
❌
✅
Header / total / first / last column overrides
Table totals row
✅
❌
✅
Per-column aggregation function preserved
Custom table styles
✅
❌
⚠️
Built-in styles fully wired; user-authored styles round-trip-only. Built-in TableStyleLight* / Medium* / Dark* gallery ships in TableStyleSelector (theme-accent-derived), and a table picks one via TableView.styleName. User-authored XLSX <tableStyle> blocks round-trip preservation works — parser exposes them via workbook.workbookStyles.getCustomTableStyleExports(), exporter re-emits them via the customTableStyles arg on createExcelFile (each <tableStyleElement> re-registered as a dxf). What's NOT wired: the TableStyleSelector picker doesn't surface custom styles, useSpreadsheetState doesn't expose the list as reactive state, and applying a custom style by name to a TableView isn't a code path — host has to forward + render
AutoFilter (basic)
✅
✅
✅
Text, number, date, blank, error criteria
Filter by color
✅
✅
✅
Phase 3 shipped (XLSX + ODS round-trip)
Filter by icon
✅
❌
✅
Phase 3 shipped
Multi-column sort
✅
✅
✅
Multi-level Sort dialog (SortRangeDialog) — add / delete / reorder "then by" levels, each with column + sort-on (value / cell color / font color / icon) + order — opened from the AutoFilter dropdown's Custom sort…. Hooks accept multi-spec (onSortRange per-column SortSpecs[], onSortTable multi-dimension overload). The context-menu range "Sort A→Z / Z→A" remains single-column
Sort by color / icon
✅
❌
✅
Selectable per level in the Sort dialog; color / icon swatches are auto-discovered per column (shared with the filter's discovery via useColumnColorIcons)
Custom sort orders / lists
✅
❌
✅
Surfaced in the Sort dialog from useSpreadsheetState({customAutofillLists}); the chosen list drives spec.customList
Data validation
✅
✅
✅
list, range, decimal, whole, date, time, textLength, custom formula. Commit-time enforcement (Excel errorStyle) — see the error/input messages row
Data validation error/input messages
✅
✅
✅
Authorable in the rule editor (input-message title/body + error-alert style/title/body) and enforced on direct cell entry: stop rejects the value (blocking modal, cell unchanged, focus stays); warning / information allow override (OK / Cancel). Input message renders as a cell tooltip. Paste / fill keep the flag-only red marker; CUSTOM_FORMULA rules fall back to flag-only (no synchronous eval at commit). The <ValidationAlertDialog> is host-mounted
Dropdown lists from range
✅
✅
✅
Dropdown lists (inline values)
✅
✅
✅
Schema-based tables (typed columns)
❌
❌
✅
Custom — not an Excel feature
Calculated columns
✅
❌
✅
Auto-fill formula on insert / paste
Pivot tables (rendering imported)
✅
✅
✅
XLSX pivotCacheDefinition + pivotTable round-trip; rendered through the same libs/pivot pipeline as authored pivots
Pivot tables (authoring UI)
✅
✅
✅
DuckDB-powered analytical layer (PIVOT operator + JS post-transforms)
Pivot row / column / value fields (drag, reorder, show-hide)
✅
✅
✅
Drag-and-drop field list panel; per-field hide checkbox in editor
Pivot subtotals + grand totals toggles
✅
✅
✅
Per-pivot showSubtotals + showRowGrandTotals + showColumnGrandTotals (PivotEditor's Totals panel)
Pivot sort (row label, column label, value field)
✅
✅
✅
Tri-state ↑/↓/none on every field; value-field sort handles BOTH the grouping-only alias shape ("Field") and the column-pivoted shape (agg(Field))
Pivot label filter (set values, search, select-all)
✅
✅
✅
Per-field filter popover with searchable checkbox list
Pivot Top N filter
✅
✅
✅
Top / Bottom × N by any value field — emits IN (SELECT ... ORDER BY agg(byField) LIMIT N) against the SOURCE CTE
Pivot refresh button + auto-refresh on source mutation
✅
✅
✅
Manual refresh icon in PivotEditor; sourceDataVersion invalidates results when source range mutates
Pivot drilldown (double-click value cell)
✅
✅
✅
onDrillDownAtCell returns the underlying source rows for the clicked aggregate
Pivot "Show Values As" (% of total, % of row, % of column, running total, rank)
✅
✅
✅
Per value field — post-aggregation JS transform; PERCENT / NUMBER number-format derived from the chosen mode
Pivot field grouping (date by period, numeric by bucket size)
✅
✅
✅
DuckDB EXCLUDE-based SOURCE rewrite (date_trunc / FLOOR) — period whitelisted to prevent SQL injection
GETPIVOTDATA()
✅
✅
✅
2D matrix header-matching lookup; resolves the value cell for a given (field=value, …) tuple
Slicer ↔ pivot wiring
✅
❌
✅
Slicer selection applies as a label filter to bound pivots; pivot re-runs through the same filter pipeline
Pivot tables (XLSX round-trip of cache+def)
✅
❌
✅
refreshOnLoad="1" so Excel rebuilds the cache from the live source; positions, rows/columns/values, aggregation function, sort + filter state all preserved
Calculated fields / calculated items
✅
❌
❌
Deferred (Phase 10)
Slicers (table-backed)
✅
❌
✅
Create/move/resize/delete + XLSX + ODS round-trip
Slicers (pivot-backed)
✅
❌
✅
Slicer reads distinct values from the bound pivot's source range (column matching fieldName); selection routes through onFilterPivot → applySlicerSelectionToPivots → pivot's filter pipeline. XLSX export of the pivot OLAP cube cache itself deferred — table-backed slicers ship in full
Timeline filters
✅
❌
❌
Deferred
Conditional formatting
Number-based rules
✅
✅
✅
greater / less / equal / between, etc.
Text-based rules
✅
✅
✅
contains / starts with / ends with / equals
Date-based rules
✅
✅
✅
today, yesterday, this week, etc.
Custom formula rules
✅
✅
✅
Gradient / color scale (2-stop, 3-stop)
✅
✅
✅
Data bars
✅
❌
✅
dataBarRule round-trips XLSX + ODS (see cf-roundtrip.spec.ts)
Icon sets
✅
❌
✅
iconSetRule round-trips XLSX + ODS (3TrafficLights1, 3Arrows, 5Rating, etc.)
Top / bottom N rules
✅
❌
⚠️
Implementable via custom formula
Duplicate / unique rules
✅
❌
✅
Range re-anchor on insert/move
✅
✅
✅
updateRangedRulesOnStructuralChange + updateRangedRulesOnReorder
Charts
Column charts (clustered / stacked)
✅
✅
✅
Bar charts
✅
✅
✅
Line charts (smooth / stepped)
✅
✅
✅
Area charts
✅
✅
✅
Pie / doughnut charts
✅
✅
✅
Scatter charts
✅
✅
✅
c:scatterChart import — each series carries c:xVal/c:yVal instead of the c:cat/c:val shape used by other charts. Export emits the same. Renders via plotly/echarts scatter
Bubble charts
✅
✅
✅
c:bubbleChart — adds c:bubbleSize (third dimension). Bubble size scales calculated via createBubbleSizeScale. Round-trip preserves all three axes
Pie of Pie / Bar of Pie (c:ofPieChart)
✅
❌
⚠️
Renders as a plain pie — we surface the data and slices but don't reconstruct the secondary slice expansion. Round-trips through the pie path
Cross-sheet data references
✅
✅
✅
A chart on Sheet1 can pull its data from 'Other Sheet'!$A$1:$A$10. Parser resolves the prefix to the actual data sheet's sheetId so every series source is pinned correctly; exporter re-encodes the sheet name
Radar charts
✅
❌
✅
Creatable from the chart-type picker (standard / with-markers / filled) and rendered natively — echarts radar coordinate + plotly scatterpolar (utils/radar.ts)
Treemap
✅
✅
✅
Sunburst
✅
✅
✅
Stock (line-derived)
✅
❌
✅
Creatable from the picker (HLC / OHLC) and rendered as line series in echarts + plotly (utils/stock.ts toLineSeries); a toCandlestick transform is also available for renderers that prefer OHLC bodies
Stock (OHLC / candlestick)
✅
❌
✅
OHLC / VOHLC variants render as a native candlestick — echarts candlestick series + plotly candlestick trace (utils/stock.ts toCandlestick). Pickable from the chart-type picker (Stock → OHLC)
Waterfall
✅
❌
✅
Renders in echarts + plotly. Phase 5.5b: full c15:waterfallChart in mc:Choice + c:barChart fallback — Excel 2016+ renders natively
Funnel
✅
❌
✅
Renders in echarts + plotly. Phase 5.5b: full c15:funnelChart in mc:Choice + c:barChart fallback — Excel 2016+ renders natively
3D variants (bar3D / column3D / pie3D / line3D / area3D)
✅
❌
❌
Deferred — needs echarts-gl + plotly mesh3d construction
Surface
✅
❌
❌
Deferred (same dep as 3D)
Histogram
✅
✅
✅
Native histogram (echarts/plotly) with auto/Sturges binning + bin-count override. Phase 5.5b: exporter emits full c15:histogramChart in mc:Choice with c:barChart fallback — Excel 2016+ renders natively
Box & whisker
✅
❌
✅
Native boxplot (echarts boxplot series, plotly box trace). Phase 5.5b: full c15:boxWhiskerChart (quartileMethod, showMean, showOutlier) in mc:Choice + c:barChart fallback — Excel 2016+ renders natively
Pareto
✅
❌
⚠️
Constructible via column + line combo
Combo (mixed series types)
✅
✅
✅
Per-series seriesChartType picker in chart-editor (bar/column/line/area)
Dual-axis (secondary axis)
✅
✅
✅
Per-series Plot on secondary axis checkbox in the chart editor; rendered as a second yAxis in echarts (yAxisIndex) and yaxis2 in plotly. secondaryValueAxisOptions round-trips; the per-series flag is editor-set (the XLSX parser doesn't tag series by axis)
Chart titles, legends, axis labels
✅
✅
✅
Data labels (value / category / percent)
✅
✅
✅
Rendered from spec and authorable in the chart editor — master "Show data labels" toggle + value / category name / series name / percentage checkboxes + label position (center / inside / outside / inside-end / outside-end / best-fit)
Trendlines
✅
✅
✅
linear / polynomial / exponential / logarithmic (+ power, moving-avg). Per-series toggle + type picker in the chart editor; regression computed in utils/trendline.ts (with R² + equation) and drawn as an overlay line in both echarts + plotly
Error bars
✅
✅
✅
Per-series toggle (fixedVal / percentage / stdDev / stdErr) in the editor; magnitudes from utils/error-bars.ts, drawn via an echarts custom series + plotly native error_y. custom range-based bars are unsupported (the model carries no plus/minus range fields)
Chart styles / colors
✅
✅
✅
Chart series gradient fill
✅
✅
✅
Per-series gradient toggle in the chart editor. Rendered: echarts paints faithfully via graphic.LinearGradient (cardinal angles axis-aligned, utils/gradient.ts); plotly degrades to a representative solid color (no per-trace gradient fill). Linear (degree) + path (left/right/top/bottom insets). XLSX exporter emits <a:gradFill> inside <c:spPr> with EMU-per-mille positions + 60000ths-of-a-degree angle. Parser hydrates from the same shape. ODS exporter emits <draw:gradient> defs in automatic-styles + references via draw:fill-gradient-name on the series style; ODS-side parser hydration is deferred (rare in the wild). Field on ChartData.gradient
Chart move / resize
✅
✅
✅
Chart editing UI
✅
✅
✅
Formula-driven titles & labels
✅
✅
✅
Range references resolved at render
Visual content
Embedded images
✅
✅
✅
Insert, move, resize, replace
Image properties (brightness/contrast/transparency/crop/z-order)
✅
⚠️
❌
Deferred (Phase 8); only position/size round-trips
Shapes (rectangles, lines, arrows, text boxes)
✅
✅
⚠️
Imported; export deferred (Phase 8)
SmartArt
✅
❌
❌
Out of scope
Sparklines — line / column / win-loss
✅
✅
✅
XLSX + ODS round-trip. Axis options round-trip too: displayEmptyCellsAs (gap/zero/span), dateAxis, markers, high/low/first/last/negative point highlights, displayXAxis, lineWeight, manualMax/manualMin, minAxisType/maxAxisType — all carried through SPARKLINE() formula options
Hyperlinks (URL + tooltip)
✅
✅
✅
Internal links (Sheet!A1)
✅
✅
✅
Comments (legacy)
✅
❌
✅
Author + rich text
Comments (threaded with replies)
✅
✅
❌
Tier 1 blocker — commentsThreaded.xml not parsed
Citations / inline annotations
❌
❌
✅
Custom — surfaces inside =FILTER source attribution & similar
Mentions (@user)
❌
✅
✅
Mentions component bundled
Cell tooltips / popovers
✅
✅
✅
Programmatic via getCellPopoverContent
Cell renderers (custom)
❌
❌
✅
Custom — render React components inside cells
Structured cell renderers
❌
❌
✅
Custom — schema-driven rendering
Workbook structure
Multiple sheets
✅
✅
✅
Sheet tabs UI
✅
✅
✅
Drag-to-reorder
Sheet rename
✅
✅
✅
Sheet duplicate
✅
✅
✅
Sheet move / reorder
✅
✅
✅
Sheet color
✅
✅
✅
Hide / show sheets
✅
✅
✅
Very-hidden sheets
✅
❌
✅
XLSX state="veryHidden" preserved
Sheet protection (cell-level locked metadata)
✅
✅
✅
Preserved on round-trip
Sheet protection (enforcement)
✅
✅
✅
Every mutation hook in libs/spreadsheet-state/hooks/ gates through useCanEditCellRange / useCanEditSheet. The host provides the policy via SpreadsheetContext.canEditCell + isSheetProtected (defaults are permissive — protection metadata round-trips but only gets enforced when the host wires a policy). Gates cover: single + batch cell edits, paste, fill, delete cells / rows / columns, insert cells / rows / columns, move, merge / unmerge, sort (range + table), filter table, change formatting, change decimals, change border, clear formatting, paint format, hide / show rows + columns, group / ungroup, resize, conditional-formatting CRUD, data-validation CRUD, named-range create + update. Streamed batch writes are gated up front before the stream starts.
Workbook protection
✅
✅
✅
Structural-protection gate (useCanEditWorkbook) refuses add / delete / rename / move / duplicate / hide / show / tab-color when the host sets isWorkbookProtected={true} on the canvas grid (matches Excel workbookProtection lockStructure="1"). Cell edits remain governed by per-sheet protection.
Named ranges
✅
✅
✅
External links / connections
✅
❌
⚠️
Read-only; not actively refreshed
Themes (light / dark)
✅
❌
✅
Light/dark variants generated from workbook theme
Custom themes
✅
❌
⚠️
Colors preserved; full theme structure simplified
Zoom / scale
✅
✅
✅
Per-sheet zoomScale (10–400) round-trips xlsx; exposed from useSpreadsheetState; canvas scale prop already supports the full 25–400% range via Ctrl+wheel + ScaleSelector
Grid lines toggle
✅
✅
✅
Print setup (page setup, headers, footers)
✅
✅
⚠️
Print preview dialog (PrintPreviewDialog) ships: paper size (Letter / A4 / Legal / Tabloid), portrait/landscape, scale (Normal / Fit width / Fit page / Custom %), margins (Normal / Narrow / Wide / Custom), horizontal + vertical alignment, show-gridlines, scope (Current sheet / Workbook / Selection), Cmd/Ctrl+P shortcut, paginated previews + iframe-driven window.print() with @page rules. Headers/footers template language (&L/&C/&R zones, &P/&N/&D macros) and repeat-frozen-rows/cols on each printed page are the remaining gap.
Page breaks
✅
✅
⚠️
Auto-pagination renders correctly in the print preview (greedy fit, down-then-over page order — same as Excel's pageOrder = "downThenOver" default). Drag-to-edit custom page breaks is the remaining gap; the underlying <rowBreaks> / <colBreaks> XLSX metadata still round-trips.
Multi-instance spreadsheets on one page
❌
❌
✅
Custom — instanceId isolates state
Sheet switcher (jump-to-sheet)
❌
❌
✅
Component bundled
Collaboration
Real-time multi-user editing
✅ (online)
✅
✅
Backends: YJS, ShareDB, Supabase Realtime
User presence / avatars
✅
✅
✅
Per-cell active-user overlay
Cursor / selection broadcast
✅
✅
✅
Conflict resolution (OT / CRDT)
✅
✅
✅
OT (ShareDB) + CRDT (YJS) options
Comments threading
✅
✅
❌
(Same gap as in Visual content section)
Version history
✅
✅
⚠️
Diff via libs/version-comparison; full version-history UI is host's responsibility
@mentions in cells
❌
✅
✅
Import / export — detailed
XLSX import
Cell values, types, formulas
✅
Including shared strings, inline strings, rich text runs
Cell formatting (fonts, fills, borders, alignment, number formats)
✅
Theme tints resolved; ~68 built-in number formats
Merged cells
✅
Hyperlinks (with tooltips)
✅
Comments (legacy comments.xml)
✅
Threaded commentsThreaded.xml not parsed
Hidden / very-hidden sheets
✅
Row heights / column widths
✅
Hidden rows / columns
✅
Separates hiddenByUser vs hiddenByGroup
Outline / grouping (rows + cols, nested)
✅
outlineLevel, collapsed, outlinePr summary direction
Freeze panes
✅
Tab color
✅
Named ranges (workbook + sheet scope)
✅
Tables (with totals row, banded styling)
✅
AutoFilter (text, number, date, color, icon, blank, error)
✅
Data validation (all 9 rule types)
✅
Conditional formatting (boolean, gradient, data bars, icon sets, custom formula)
✅
All rule types round-trip
Charts (column / bar / line / area / pie / doughnut / scatter / bubble / treemap / sunburst / radar / stock-line)
✅
Charts (histogram / box & whisker / waterfall / funnel)
✅
Parser detects both the new mc:AlternateContent + c15 element shape (what we now emit and what Excel emits) and the legacy c:extLst marker (for backwards compat with files we wrote before Phase 5.5b)
Charts (3D / surface)
❌
Deferred
Embedded images + drawings
✅
Position & size only
Shapes (rectangles, lines, arrows, text boxes)
⚠️
Read; export deferred
Sparklines
✅
Slicers (table-backed)
✅
Pivot slicers not yet
Pivot tables
✅
Parses xl/pivotCache/* + xl/pivotTables/* — A1 source range, sheet prefix stripped, agg-fn normalized, sort + filter state hydrated
Themes (colors + fonts)
✅
Light + dark variants generated
Iterative calculation settings
✅
External links / connections
⚠️
Cached; not refreshed
Macros / VBA
❌
Discarded for security
ActiveX / OLE / linked data types / SmartArt / Cube functions
❌
Out of scope
Password-encrypted file decryption
❌
Not implemented
XLSX export
Cell values, formulas, shared strings, inline strings
✅
Full formatting (fonts/fills/borders/align/number formats)
✅
Merged cells
✅
Hyperlinks
✅
Comments (legacy)
✅
Hidden / very-hidden sheets
✅
Row heights / column widths
✅
Hidden rows / columns
✅
Outline / grouping (rows + cols, nested)
✅
outlinePr only emitted when non-default
Freeze panes
✅
Tab color
✅
Named ranges (workbook + sheet scope)
✅
Tables (with totals row + banded styling)
✅
AutoFilter (incl. color + icon criteria)
✅
Data validation
✅
Conditional formatting (boolean, gradient, data bars, icon sets, custom formula)
✅
Charts (column / bar / line / area / pie / doughnut / scatter / bubble / treemap / sunburst / radar / stock-line)
✅
Charts (histogram / box & whisker / waterfall / funnel)
✅
Emitted as mc:AlternateContent with full c15:histogramChart/c15:boxWhiskerChart/c15:waterfallChart/c15:funnelChart in mc:Choice (Excel 2016+ renders natively) plus a c:barChart in mc:Fallback for older Excel
Embedded images
✅
Base64 + relationship wired
Sparklines
✅
Slicers (table-backed)
✅
Themes (colors + fonts)
✅
Iterative calculation settings
✅
Password encryption (CFB)
✅
Optional password arg in createExcelFile
Shapes export
❌
Deferred
Pivot table cache + definition
✅
Emits xl/pivotCache/pivotCacheDefinitionN.xml + xl/pivotTables/pivotTableN.xml with refreshOnLoad="1"; workbook <pivotCaches> and per-worksheet relationships wired
Pivot slicer cache (OLAP)
❌
Deferred — buildSlicerCacheXml() currently returns null for pivot-backed slicers (table-backed slicers ship)
Custom table styles
✅ (round-trip only)
<cellStyles> + <tableStyles> blocks emitted from customTableStyles / namedCellStyles args on createExcelFile; element formats re-registered as dxfs. Toolkit-level preservation only — the in-app pickers (TableStyleSelector / CellStyleSelector) don't surface user-authored styles yet
Real-time collab metadata
❌
Spreadsheet-internal; intentionally not emitted
ODS import
Identical bucket coverage as XLSX import. ODS-specific notes:
Outline (<table:table-row-group> / <table:table-column-group>)
✅
table:display="false" → collapsed; both axes & nested
Sparklines (LibreOffice extension)
✅
calcext:sparkline-groups parsed
Database ranges (ODS's AutoFilter equivalent)
✅
Conditional formatting (LibreOffice extension)
✅
Data validation
✅
Charts
✅
Sheet protection metadata
⚠️
Parsed; same enforcement gap as XLSX
Pivot tables
⚠️
Structure parsed; same Phase 10 gap as XLSX
outlinePr direction
⚠️
ODS has no native equivalent; defaults applied on import
ODS export
All formatting, formulas, sheet structure
✅
Outline groups
✅
Nested <table:table-row-group> / <table:table-column-group> with table:display="false"
Tables → database ranges
✅
Sparklines
✅
LibreOffice extension element emitted
Charts
✅
Slicers (table-backed)
✅
LibreOffice subset
Images
✅
outlinePr.summaryBelow / summaryRight (non-default)
❌
Not persisted — ODS has no equivalent attribute
CSV import / export
Plain values
✅
✅
Type inferred on import (number / date / boolean / string)
Custom delimiter
✅
✅
Comma, semicolon, tab, custom
Quote escaping
✅
✅
RFC 4180
Encoding (UTF-8, UTF-16)
✅
✅
BOM detection
Multi-sheet
❌
❌
CSV is single-sheet by spec
Formatting / formulas
❌
❌
Lost on round-trip
Worker-based parsing for large files
✅
N/A
Engineering capabilities (developer-facing)
These are features that don't have an Excel equivalent — they're framework / SDK capabilities:
Headless UI mode
Components render without forcing a specific UI shell
useSpreadsheetState hook
Single hook that wires every callback + state slice
Imperative spreadsheet API
Programmatic access via ref handle (set value, get range, etc.)
Multi-instance spreadsheets
Multiple independent grids on one page via instanceId
Calculate on-demand
Toggle automatic recalculation; queue dispatcher exposed
Real-time data binding
Stream external values into cells (e.g. live ticker)
Web-worker calculation
Off-main-thread formula engine
Custom cell editors
Replace per-type editor (e.g. richer date picker)
Custom cell renderers
Replace per-cell paint with React component
Structured cell renderer
Schema-driven cell rendering
Custom formula evaluation
Inject custom function implementations
Tokenizer access
Parse formulas independently of the engine
Cell format registry
Register custom number formats globally
Shared strings management
Manual control of the workbook's interned string pool
Mentions
@user mention engine bundled
Localisation
i18n for UI strings (formula names still English)
Lazy loading / infinite scrolling
Render only what's visible; load rows on demand
Export canvas as image
Serialize current viewport to PNG
OpenAI / ChatGPT integration
Inline AI prompt + apply (magic fill, formula generation)
Drag and drop (files)
Drop CSV / XLSX onto the canvas to import
Insert date/time helpers
Toolbar action
Insert link / image editor components
Bundled
Navigate to range / named range editor
Bundled components
Sheet status component
Pre-built bottom-bar status widget
Range selector / selection input components
Reusable picker controls
Version comparison
Diff two snapshots and surface changes
Currently unsupported (deferred)
This list mirrors docs/compat/remaining-gaps.md. Tier 1 items can silently lose data on round-trip:
Tier 1 — data-loss blockers:
Sheet protection enforcement ✅ shipped —
useCanEditCellRange/useCanEditSheetgates threaded through every mutation hook; host provides the policy viaSpreadsheetContext.canEditCell+isSheetProtectedWorkbook protection enforcement ✅ shipped —
useCanEditWorkbookgates structural sheet ops (add / delete / rename / move / duplicate / hide / show / tab-color); host opts in viaisWorkbookProtected={true}on the canvas gridThreaded comments (with replies, resolved state)
Phase 6 (formula) remainder:
Cross-workbook references
[Book.xlsx]Sheet!A1GROUPBY / PIVOTBY ✅ shipped —
LambdaFunctionsentries built on top of the existing LAMBDA infra. Tokenizer-aware substitution + Excel-native{a,b,c}array literals; no chevrotain grammar changesFORECAST.ETS* family
Phase 7 — LAMBDA family:
LET ✅ shipped (source-level expansion)
LAMBDA + MAP / REDUCE / BYROW / BYCOL / SCAN / MAKEARRAY ✅ shipped (IIFE inlining + runtime lambda values via
__RNC_LAMBDA__preprocessor; HOFs registered infunsNeedContextand re-invoke the parser per element)LET-bound lambdas callable like functions ✅ shipped (Function-token substitution in
substituteNamesInBody)Closures via LET capture ✅ shipped (LET runs first, bakes values into lambda body strings)
Workbook-named LAMBDAs callable as
=MyFunc(args)✅ shipped —_callFunctionresolves viaonVariableand accepts three shapes: pre-built lambda value,{ref, value}wrapper, or raw"=LAMBDA(...)"source string (parsed + applied). Works for both the main-thread calc and the worker since both use the rebuilt parser distDep parser walks lambda body strings ✅ shipped (
__RNC_LAMBDA__branch in DepParser.callFunction uses a fresh inner instance)Recursive lambdas (e.g.
LET(fact, LAMBDA(n, IF(...)), fact(5))) ❌ deferred — body-reparse at runtime loses the LET binding; needs a runtime registry that survives the per-call re-parseNamed-range formula evaluation (general —
=MyVarwhere MyVar ==SUM(A1:A10)) ✅ shipped — Excel virtual-cell model with real DAG edges, unified topological sort, scope-aware (workbook + per- sheet) keys, order-independent batch registration, and JSON round-trip. See "Formulas & functions" table above for the user- visible rows.
Phase 8 — visual fidelity:
Image brightness / contrast / transparency / z-order / cropping
Shape export (rectangles, lines, arrows, text boxes)
Gradient cell fills ✅ shipped —
<gradientFill>round-trip + canvas paint (linear + path)
Phase 9 — view & UX:
RTL layout
Non-frozen pane split
Phase 10 — pivot tables:
Full XLSX cache + definition round-trip ✅ shipped — import (
pivots.ts) + export (pivot-builder.ts); refreshOnLoad rebuilds cache from live sourceAuthoring UI (drag rows/cols/values, hide fields, subtotals + grand-totals toggles, sort, label filter, Top N, refresh, drilldown) ✅ shipped
Show Values As (% of total / row / column, running total, rank ↑/↓) ✅ shipped — PERCENT/NUMBER number-format applied to value + total cells
Field grouping (date by period, numeric by bucket) ✅ shipped via DuckDB EXCLUDE-based SOURCE rewrite
GETPIVOTDATA() ✅ shipped
Slicer ↔ pivot wiring ✅ shipped (label-filter pipeline)
Calculated fields / calculated items ❌ deferred
Pivot-backed slicer OLAP cube cache export ❌ deferred (table-backed slicers ship)
Pivot table styles (PivotStyleLight/Medium/Dark exporter mapping) ❌ deferred
Conditional formatting on pivot data cells ❌ deferred
Phase 11 — niche:
Bond pricing functions (PRICE, ODDFPRICE, ODDLYIELD)
Custom table style export ⚠️ partial — toolkit round-trip via
customTableStylesarg oncreateExcelFileships, but theTableStyleSelectorpicker doesn't list user-authored styles andTableView.styleNameisn't applied throughuseSpreadsheetStatefor them. UI wiring deferredWorkbook named cell styles UI gallery ⚠️ partial — toolkit round-trip via
namedCellStylesships, butCellStyleSelector'suserDefinedStylesprop isn't auto-populated from imported named styles. UI wiring deferredLocalized function names
Phase 12 — linked data types:
Linked data type cells (Stocks, Geography, Wolfram) — partial: the
entity-shapedstructuredValuemodel +dataTypeProvidersAPI already lets hosts wire custom providers (seestockProviderin the storybook), and=A1.fieldfield-access syntax works. Round-tripping the OOXMLlinkedDataTypeelement + Excel's built-in Stocks/Geography panel is deferred. Not blocked by anything fundamental.
Explicitly out of scope
Macros / VBA / ActiveX / OLE
Power Query / Power Pivot / external data connections
SmartArt graphics
Cube functions (CUBEMEMBER, etc.)
STOCKHISTORY (live market data)
Custom XML parts
3D / surface charts (3D needs
echarts-glpeer dep)Google Apps Script
IMPORTRANGE / GOOGLETRANSLATE / GOOGLEFINANCE (Sheets-specific functions tied to Google services)
Summary
The Rows n Columns Spreadsheet offers high-fidelity compatibility with Excel and Google Sheets across the features most apps use:
Fully compatible:
All basic & advanced editing operations
Full cell formatting palette (fonts, colors, borders, alignment, number formats, rotation)
~378 Excel-compatible functions including dynamic arrays + modern array helpers
Named ranges — range-typed, static-value, formula-typed (
=MyVarwhere MyVar is a formula), and named functions (LAMBDA-typed). Excel virtual-cell DAG model with scope-aware (workbook + sheet) resolution and order-independent batch registrationTables, AutoFilter (incl. color/icon), multi-column sort, data validation
Conditional formatting (boolean, gradient, data bars, icon sets, custom formula)
Charts (column, bar, line, area, pie/doughnut, scatter/bubble, radar, stock-line, treemap, sunburst)
Embedded images, hyperlinks, sparklines, legacy comments
Multi-sheet workbooks with full sheet management
Row/column outline & grouping (XLSX + ODS round-trip)
Slicers (table-backed)
Themes (light / dark variants)
XLSX + ODS round-trip for all of the above
Password-encrypted XLSX export
CSV import/export
Built-in features Excel/Sheets don't have:
Real-time collaboration (YJS, ShareDB, Supabase) out of the box
Web-worker formula engine
Custom cell editors + renderers
Multi-instance grids on one page
OpenAI / ChatGPT magic fill integration
Schema-based tables
React-native customisation throughout
Known gaps (deferred — see Phase tables above):
Threaded comments (legacy comments work)
Recursive LAMBDA (rest of Phase 7 family + GROUPBY/PIVOTBY shipped)
Pivot table calculated fields/items + pivot-backed slicer OLAP cache (rest of Phase 10 shipped — cache+def round-trip, authoring UI, GETPIVOTDATA, show-values-as, grouping, slicer wiring)
3D / OHLC / surface charts
Macros, Power Query, Cube functions, linked data types (out of scope)
For most spreadsheet application use cases, this provides production-grade compatibility with Excel and Google Sheets — and adds collaboration + extensibility features that neither has natively.
Last updated