Documents and Spreadsheets
Write together, with no office server anywhere.
Write a document in the browser, on the phone, or on the laptop, and have somebody else type in it at the same time — with no office server anywhere, and no account to make.
MeshHold's editor is its own, and it speaks OpenDocument natively:
it reads and writes .odt and .ods in the daemon, on every platform
it runs on. There is nothing to install beside it and nothing to keep
running: the document is a file in a vault like any other, so it
replicates, versions, mounts, shares and stays available offline by the
machinery that was already there.
What the editor does
Headings and paragraph styles, character styles, fonts and colour, lists with multi-level numbering, tables with borders and shading, pictures, links, footnotes and endnotes, bookmarks and cross-references, a table of contents, find and replace. Comments you can resolve, and tracked changes you can accept or reject. Pages that look like pages — the same page LibreOffice prints, measured against it rather than approximated, and drawn as the paper ending and the next sheet beginning rather than as a line across one long page.
Things go on the page as well as in it: shapes and text boxes, a drawing surface for a diagram, charts that carry their own numbers, equations typed in LaTeX and stored as MathML, and a watermark across every sheet. Text runs in two or three columns — across the selected paragraphs, or across the whole page. The document's own properties — title, subject, keywords, the author's name, and any custom field the file carries — are edited in a panel of their own.
The document's own styles are a palette rather than a fixed list: the ones the file already carries are all there, you can change one, put it back to what it inherits, take away one nobody is using, and make a new one out of the paragraph you are looking at. Colour is a picker with any value in it, not eight names. The ruler counts in millimetres, centimetres or inches, whichever you set it to, and a table's columns are dragged by their edges or given an exact width.
Spreadsheets get cells and formats, formulas, several sheets, charts, conditional formatting and data validation. Charts sit on the sheet where a spreadsheet puts them, are dragged and resized there, and go past the kind and the colours: axes with a pinned minimum and maximum, point markers, a legend box, and axis labels in a number format taken from the same list a cell uses. A date typed into a cell becomes a date, and there are functions for the arithmetic that is not a number of days — the month after the thirty-first of January, or five working days from Friday with the bank holidays taken out.
The analysis layer above the grid is there too. Pick a block, press
Pivot, and say what goes down the side and what gets summarised: the
table is worked out in the daemon and appears on a sheet of its own, with
a page field at the top to filter it by.
Named ranges can be defined and used in formulas — type a name into the
address box over a selection and it becomes that name. A formula can read
a cell in another spreadsheet in the same folder. An array formula
computes a block of answers from one expression. Duplicates are removed
and a column of Doe, John is split in two, both saying what they will do
before they do it. A sheet can be hidden, or protected from editing with a
few cells left open to fill in.
Both editors take handwriting: a note written with a pen or a finger goes into the file as a picture with the strokes kept inside it, so opening it again gives back the strokes rather than a flat image. On a sheet it is anchored in a cell and moves like a chart.
None of that needs a server. The document is parsed and written by the daemon on your own machine, and drawn by the browser in front of you.
Editing together
Open the same document on two nodes and both people type into it. The changes travel node to node over the mesh, so two laptops on a local network with no internet still edit the same document — there is no office server to be unavailable, because there is no office server.
What each person sees is who else has it open and where their edits land. What nobody has to do is resolve a conflict: the document is a CRDT, so two versions that diverged — one of them offline for an hour — merge rather than fork.
Opening a .docx somebody sent you
The editor's format is ODF. A .docx, .doc, .rtf, .xls, .xlsx
or .ppt is converted first, by LibreOffice on whichever node in
your network has one.
Right-click the file and the menu lists the nodes that can do it:
Convert "contract.docx"
▸ Convert here LibreOffice 25.8
▸ Convert on homelab LibreOffice 25.2
─────
No node in this network can convert.
Install LibreOffice on a desktop node to enable this.
Three things are worth knowing about that menu.
The list is real before you click it. Each node was asked whether it holds this vault's key and whether its LibreOffice works — not whether it claims to. A node whose LibreOffice is installed but broken says so rather than appearing and failing.
The conversion happens where the file already is. The node doing the
work holds the vault key, so it reads the blocks the ordinary way and
writes the result back as a new file beside the original. Nothing is
uploaded, and the original is never touched — the .odt appears next to
the .docx, and if one is already there it is left alone.
A phone converts on the desktop. LibreOffice does not run on Android and never will, so a phone asks a node that shares the vault with it. A network with no LibreOffice anywhere converts nothing, which the menu says plainly instead of hiding the option.
Conversion is one-way. The .docx becomes an .odt and from then on it
is an ODF document; the original stays where it was.
Exporting
Two exports, and which you get depends on which control you press.
Print is the built-in one. The editor lays out real pages, so the browser's own print pipeline produces a PDF that matches what you were looking at. It needs no node, no LibreOffice and no network, and it works on a phone.
Export… goes through LibreOffice, for what print cannot do: another
format (.docx, .xlsx, .rtf, CSV), or a PDF carrying
- a watermark across every page,
- a password to open it,
- restrictions on printing, editing and copying,
- PDF/A for an archive,
- or only some pages.
Those options need LibreOffice 7.4 or newer on the node doing the work. Against an older one the dialog offers the format and hides the options, rather than showing a checkbox that would quietly do nothing.
One caveat said plainly: PDF permissions are enforced by the reader, not by the file. A compliant viewer honours "no printing" and a determined one ignores it. Treat them as a stated intention rather than as protection.
Deciding who may use your machine
Conversion spends the CPU of whichever node does it, so the node's owner decides.
Work for peers in Settings is on by default: any node in your network may ask this one to convert something. Turning it off removes this node from everyone else's menu within seconds and refuses anything already asked. It also pauses itself while the device is in low power — a phone saving its battery has not agreed to spend it on somebody else's document.
Only nodes with a work key narrows that further, for a network with
a rented server or a half-trusted guest in it. Mint a key with the
jobs capability, hand it to the nodes you want, and everyone else is
refused.
Neither switch is a data boundary, and it is worth being clear why. A node that converts your document already holds the vault key — that is the whole arrangement, and it is why nothing has to be uploaded. What these switches control is CPU, not access: a node you would not trust with the document should not be in the vault in the first place.
Where documents live
In a vault, as files. That is not a detail — it is why:
- every save is a version, and the whole history is one click away;
- a document replicates to the nodes that hold the vault, so it is on your laptop when the phone that wrote it is off;
- it can be mounted as a drive and opened in desktop LibreOffice or Word instead, if that is what a particular document needs;
- it can be handed to somebody through a public link, decrypted in their browser;
- and it is available offline, because it was never anywhere else.
Against ONLYOFFICE and Google Docs
Three editors that all let two people type in one document, and that is
about where the agreement ends. ONLYOFFICE Docs is an office suite
with a server behind it: you install Docs on a machine, integrate it
with a storage system, and it opens .docx natively because OOXML is
its own format. Google Docs is a service: nothing to install at all,
and the document lives in Google's storage in Google's own format.
MeshHold's editor is neither — it is ODF in the daemon you are already
running, with the document sitting in a vault as a file.
These are our rows, which is the weaker position to argue from, so where
a — is a design decision rather than a thing not yet built it says so,
and the groups where MeshHold loses outright — things placed on the
page, and everything under Beyond typing — are in the table rather
than left out of it.
| MeshHold | ONLYOFFICE Docs | Google Docs | |
|---|---|---|---|
| What it takes to run | |||
| Server to install and keep running | None — the daemon you already run | Docs server, ~4 GB RAM, 40 GB disk1 | None — it is Google's |
| Account to sign in with | None | Whatever hosts it | A Google account |
| Editing with no internet at all | ✓ | A Docs server on that LAN, or the desktop app | Chrome or Edge, plus the offline extension |
| In a phone browser | ✓2 | ✓ plus iOS and Android apps | ✓ plus iOS and Android apps |
| Desktop application | Windows and Linux; no macOS build | ✓ Windows, macOS, Linux | — browser only |
| Licence | AGPL-3.0 | AGPL-3.0 + §7, or commercial | Proprietary |
| Price | Free | Free Community; paid Enterprise | Free personal; paid Workspace |
| The file, and the formats | |||
| Native format | ODF — .odt read and written in the daemon | OOXML — an .odt is converted on open and again on save3 | Google's own — .odt and .docx are import and export |
| Parts of the file nobody touched survive a save byte for byte | ✓4 | — | — |
Opens .docx, .doc, .rtf | Converted first, by LibreOffice on a node that has it | ✓ natively | ✓ on import |
Saves .docx or .rtf | Exported through LibreOffice | ✓ | ✓ as a download |
| Document properties — title, author, keywords | ✓24 | ✓ | ✓ |
| Opens a password-protected document | — refused, and it says why5 | ✓ | — |
| Print, or save as PDF | ✓ | ✓ | ✓ |
| PDF export with an open password, print or copy restrictions, PDF/A | ✓ LibreOffice 7.4+ on a node6 | A password on a PDF, in the desktop app | — |
| Writing and formatting | |||
| Bold, italic, underline, strikethrough, super- and subscript | ✓ | ✓ | ✓ |
| Font, size, colour, highlight | ✓ | ✓ | ✓ |
| Copy and paste formatted content, in and out | ✓ | ✓ | ✓ |
| Format painter, clear formatting | ✓ | ✓ | ✓ |
| Paragraph styles | ✓7 | ✓ full gallery, custom styles | ✓ |
| Character styles | ✓8 | ✓ | — paragraph styles only |
| Alignment, indents, a ruler | ✓ | ✓ | ✓ |
| Line spacing, space above and below | ✓ | ✓ | ✓ |
| Bulleted and numbered lists, multi-level | ✓ | ✓ | ✓ |
| Tables — insert, rows, columns, merge, split | ✓ | ✓ | ✓ |
| Column widths — dragged, evened, or an exact number | ✓ | ✓ | ✓ |
| Table borders, shading, table styles | ✓17 | ✓ | ✓ |
| Two or three columns across the page | ✓ page-wide columns drawn one under the other18 | ✓ | ✓ |
| A page break where you want one | ✓ | ✓ | ✓ |
| A different first page, or facing left and right pages | ✓9 | ✓ | ✓ |
| Part of the document landscape, or on other paper | ✓ drawn on the widest paper the document uses9 | ✓ | ✓ per section |
| Headers, footers, page numbers | ✓9 | ✓ | ✓ |
| Footnotes | ✓ | ✓ | ✓ |
| Endnotes | ✓ | ✓ | — an add-on |
| Table of contents | ✓ | ✓ | ✓ |
| Links | ✓ | ✓ | ✓ |
| Bookmarks and cross-references | ✓ page or text19 | ✓ | ✓ |
| Find and replace | ✓ | ✓ | ✓ |
| Live word count | ✓ | ✓ | ✓ |
| Spell check | The browser's own, switchable10 | ✓ built in | ✓ built in, with grammar |
| Templates | An .ott opens; no gallery | ✓ | ✓ |
| A watermark on the page | ✓ a word, not a picture20 | ✓ | ✓ |
| Things placed on the page | |||
| Pictures | ✓ | ✓ | ✓ |
| Text wrapping around a picture | ✓ | ✓ | ✓ |
| Handwriting and ink | ✓ | ✓ the Draw tab | Freehand scribble inside a drawing |
| A range from a spreadsheet | ✓ pasted as a table, not linked26 | ✓ | ✓ linked to the sheet, and updates |
| Video or audio inside the document | ✓11 | A YouTube plugin — a link, not the file | — |
| Shapes, text boxes, a drawing surface | ✓21 | ✓ | ✓ Insert → Drawing |
| A flow chart you draw yourself | ✓ no connectors that follow a shape25 | ✓ | ✓ Insert → Drawing |
| Charts in a document | ✓22 | ✓ | ✓ from Sheets |
| Equations | ✓ a LaTeX subset23 | ✓ | ✓ |
| Pages | |||
| Page boundaries while you type | ✓ | ✓ | ✓ in Pages mode |
| Paper size, margins, orientation | ✓ | ✓ | ✓ |
| Zoom, fit width, whole page | ✓ | ✓ | ✓ |
| An outline to navigate the document by | ✓ | ✓ | ✓ |
| The screen matches what prints | ✓12 | ✓ | ✓ |
| Working together | |||
| Real-time co-editing | ✓ | ✓ through Docs | ✓ through Google |
| Seeing where the others are typing | ✓ about a second behind13 | ✓ | ✓ |
| Two people co-editing on a LAN with no internet | ✓ | If the Docs server is on that LAN | — |
| Both edit offline, and both survive | ✓ | — not merged; the sync client leaves a conflict copy | Through the offline extension, set up in advance |
| Comments | ✓ | ✓ | ✓ |
| Replies inside a comment thread | — ODF carries no threads14 | ✓ | ✓ |
| Suggesting mode / tracked changes | ✓ | ✓ | ✓ |
| Version history | ✓ | ✓ | ✓ |
| Compare two versions | ✓ | ✓ compare and combine | ✓ |
| Ask an AI about the document | ✓ | ✓ a plugin, with your own key | ✓ Gemini |
| Beyond typing | |||
| Mail merge | — | ✓ | — an add-on |
| Fillable forms | — | ✓ | — |
| Macros or scripting | —15 | ✓ JavaScript macros | ✓ Apps Script |
| Plugins or add-ons in the editor | — | ✓ a marketplace | ✓ a marketplace |
| Voice typing | — | A plugin, Chrome only | ✓ |
| Spreadsheets and presentations beside it | .ods is edited; .odp is not | ✓ both | ✓ Sheets and Slides |
| Where the document lives | |||
| It is an ordinary file in your own storage | ✓ | ✓ in whatever it is integrated with | — a Drive object; .odt only on export |
| Encrypted at rest under a key you hold | ✓ | Whatever the storage does | — Google's keys |
| A server holds the plaintext while you edit | No server exists | Docs holds it | Google holds it |
| Replicates to your other devices by itself | ✓ | Whatever the storage does | ✓ Drive |
| Mount it and edit in Word or LibreOffice instead | ✓ | ✓ the desktop app | — export a copy |
| Hand it over as a link the recipient's browser decrypts | ✓16 | Whatever it is integrated with | ✓ a Google link |
Notes
- ONLYOFFICE Docs Community is a server: 4 GB of RAM and 40 GB of disk on an amd64 Linux machine, plus the storage system it integrates with. The Desktop Editors run without it, but co-editing does not — that is what Docs is for. MeshHold's editor runs inside the daemon that is already replicating your vaults, so there is no second thing to install, update or watch.
- Android, and any phone browser pointed at a node. There is no iOS app and no macOS build — if your household runs on Apple hardware, the two other columns work today and this one does not.
- ONLYOFFICE's own format is OOXML, and its
x2tengine converts an.odton open and back again on save. That is the mirror image of the trade here: MeshHold parses and writes ODF directly, and converts.docxinstead. - This is the reason for the whole design. A save rewrites the parts that changed and leaves every other archive entry — the pictures especially — as the bytes it found them, so opening a document and closing it does not quietly produce a different file. It is also what makes the storage underneath cheap: unchanged bytes re-seal to the same encrypted blocks and travel nowhere.
- An ODF package encrypts per entry and records it in a manifest that stays readable, so the editor can say "this document has a password" instead of failing on every part with "content.xml is corrupt". Opening one is not supported; the refusal is deliberate and legible.
- Watermark, open password, restrictions on printing, editing and copying, PDF/A, or a page range — produced by LibreOffice on whichever node in your network has it. Worth repeating from Exporting: PDF permissions are enforced by the reader, not by the file.
- The style menu lists what the document itself carries, the ones it is already using first, and the palette behind it does the four things a style palette does: make a new one out of the paragraph you are looking at, change one, put one back to what it inherits, and remove one. Two of those are narrower than they sound. Back to what it inherits is not "back to the way Word ships it" — ODF keeps no record of that; a style that names a parent carries only what it overrides, so dropping those overrides is the only reset the format can express, and that is what the button does and what it says. Remove is refused for a style the document is wearing and for one of ODF's own names, and it says which before you press it — the format has no cascade, so a paragraph left naming a style that is gone renders as body text in every application that opens the file afterwards.
- The menu lists every character style the document carries — Emphasis, Internet Link, whatever its author made — and applying one writes the name onto the run rather than copying what it looks like, so changing the style later still changes the words. Two styles the file may not have yet, Emphasis and Strong Emphasis, are created on demand under ODF's own names, which is what makes the button work on a document that has never had one.
- A different first page, facing left and right pages, and a landscape run in the middle of a portrait document are one thing in the format: several page styles, with a paragraph naming the one its page starts on. There is no page-break-with-a-style element in ODF and no “different first page” checkbox — the break is the paragraph.
All of it is read, edited and written: the header and footer picker chooses which page style it is editing and offers the left page's pair where the document has facing pages, and Insert → Paper starts a page on other paper from where the caret is, making the style if the document has none like it. The pagination follows — a landscape page is shorter, and the page count and the numbers in the table of contents account for it.
What is not drawn is the paper's width. The editor draws one sheet,
as wide as the widest page the document uses, and the text of a
narrower page is inset to its own measure. So a portrait page inside a
landscape document reads on screen as one with wide margins rather than
as smaller paper. Every line break, every page break and the file
itself are right; print or open it anywhere and the paper is the paper.
Why it is not drawn is measured rather than assumed — see
web/spike-paper.html, which asks a browser four questions about
laying one editable flow out as pages that are not all the same shape.
10. spellcheck is set on the editable, so the browser or the WebView
does it with whatever dictionaries the platform has, and a switch on
the Review tab turns it off for a document full of names, code or
another language. Nothing of ours checks spelling, and building it is
deliberately not planned: rewriting, explaining and translating are
things you ask the agent, which names the node and the model before
anything is sent anywhere.
11. Which costs what you would expect — the clip is inside the document, so
the document is as large as the clip. It is there because a vault can
carry it, not because a word processor usually can.
12. The oracle is LibreOffice's own PDF of the same file, compared by the
character offset each page starts at rather than by eye. Letters,
invoices and quotes come out with the page count LibreOffice gives
them. One case is open, and stated rather than hidden: a table row
taller than a page — a three-column bilingual contract is exactly that
— overflows instead of splitting across pages.
13. Presence and carets ride the sync exchange, which is a one-shot
exchange rather than an open stream, so what you see is as fresh as
the last round trip — about a second while somebody is typing. Google
and ONLYOFFICE hold a socket open to a server and are quicker; they
also need the server.
14. Not a backlog item. office:annotation in ODF has no thread, and the
two producers that tried disagree: LibreOffice 6.4 drops
loext:parent-name, and Word's .odt export flattens replies into
separate comments on the same words. A thread invented here would
survive only until somebody opened the file in either of them.
15. And not planned. A macro language is a second way to program a
document; the answer here is the agent session, which already has
approvals, a model picker and a history.
16. The key travels in the URL fragment, so the gateway serving the link
never sees it and never holds the plaintext. See
Public links.
17. Borders edge by edge with a pen you pick, cell shading, where the
contents sit in the cell, how wide the table is and which way it sits
on the page — and a Table look menu that sets all of it at once.
That menu is a name in this interface rather than a style in the file:
ODF has no table style a person picks, LibreOffice keeps its
AutoFormats in the application, and Word's do not survive its own
.odt export. So what is written is ordinary cell properties, and the
look opens the same everywhere rather than the name.
18. Two kinds of column, and they are drawn differently on purpose.
Columns across selected paragraphs are a region of the document and
are drawn side by side, which is what a newsletter is made of. Columns
across the whole page set the text at one column's width — so every
line break and every page break is where it will be on paper, and the
page count is right — and then draw the columns one under the other
with a mark where each ends, rather than side by side. Printing and
every other application show them side by side; this editor does not
yet.
19. A bookmark is placed on the selection and a cross-reference to one is
inserted as its page number or as the words it covers. Those are the
two formats ODF's own producers use; Word's longer list — “above or
below”, a numbered paragraph — is read and kept but not offered.
20. Text: a word across every page, at the angle, colour and transparency
you set, and it is a real watermark in the file rather than something
added on export. A picture watermark is a different element in the
format and is refused by name rather than half-written.
21. Text boxes hold blocks and are edited beside the page. Shapes are the
ones ODF spells the way SVG does — a rectangle, an ellipse, a line —
drawn and written natively; one of ODF's preset geometries (a star, a
banner) is read, kept exactly as the file has it and drawn as its box
with its words, because a geometry invented here would be a shape
LibreOffice draws as something else. The drawing surface makes
diagrams out of boxes, ellipses, lines, arrows, freehand and text; a
drawing is stored as a picture with its objects inside it, so it opens
everywhere and reopens here as the objects it was drawn from.
22. A chart in a text document has no sheet to read, so it carries its own
numbers in a table inside its own sub-document — which is what the
format does. Type the numbers into the chart's own grid; the kind, the
colours, the axes and the legend are the same controls the spreadsheet
has.
23. Typed as LaTeX and stored as MathML, which every browser draws and
which is what the file carries. The parser takes letters and numbers,
the arithmetic operators, ^ and _, \frac, \sqrt, \text, the
Greek letters and the common operators and functions. Anything outside
that is refused by name rather than half-translated — a formula
that comes out subtly meaning something else is the one failure
notation cannot survive. An equation LibreOffice wrote keeps its own
StarMath spelling untouched beside the MathML.
24. Title, subject, description, keywords, the initial author, and any
custom field the document carries. The dates, the editing time and the
word and character statistics are the producing application's record
of what it did and are shown read-only — stamping them here would be
writing somebody else's history.
25. Boxes, ellipses, lines, arrows, freehand and text, on a surface of
their own, saved as a picture with the objects inside it — so it
opens everywhere and reopens here as what it was drawn from. What
LibreOffice Draw has and this does not: a connector that attaches to
two shapes and stays attached when either is moved, and the gallery
of flow-chart shapes (a decision diamond, a terminator, a cylinder).
A diamond drawn as four lines is a diamond; one that redraws itself
when the box it points at moves is the part that is missing.
26. Select the cells, copy, and paste into the document: it arrives as an
ordinary table with the numbers in it, which is what most people want
and what survives being opened anywhere. It is not linked — change
the spreadsheet and the table in the document stays as it was — and
there is no embedded sheet object to double-click. A chart is the
other way round: a chart in a document carries its own numbers rather
than reading a spreadsheet's.
Which one to pick
ONLYOFFICE Docs if the documents that matter are .docx and they
come from Word — its fidelity is the best of the three, and the feature
list above is the longest for a reason. Expect to run a server for it.
Google Docs if nothing may be installed and everybody already has a Google account. Nothing else is as quick to start, and the collaboration is still the smoothest.
MeshHold's editor when the document should not leave your own machines: when there is no internet and two laptops still have to edit the same file, when the file has to stay a file — versioned, replicated, mountable, encrypted at rest — and when ODF is the format you actually want rather than one that gets converted twice on the way through. It is the youngest of the three, and the table above is meant to make it obvious where that shows.
The spreadsheet, against ONLYOFFICE and Google Sheets
The same three products, one editor over: ONLYOFFICE Spreadsheet Editor inside Docs, Google Sheets, and MeshHold's grid. What it takes to run each, and where each keeps the file, is the same answer as the document table above and is not repeated here.
One thing frames this one. The formula engine is deliberately small and says so — a hundred and eleven functions against four hundred and fifty, and a function it does not know keeps the value the file arrived with rather than inventing one.17 A spreadsheet here is a budget, a list, a tracker or a model; that is what it was scoped to be, and the table is the honest map of where that stops.
A tick below means the feature is there and behaves the way the row says. Where there is text beside one it is a limit worth knowing before you choose, not decoration — the detail behind a tick is in the notes under the table.
| MeshHold | ONLYOFFICE Spreadsheet | Google Sheets | |
|---|---|---|---|
| The file, and the formats | |||
| Native format | ODF — .ods read and written in the daemon | OOXML — an .ods is converted on open and again on save | Google's own — .ods and .xlsx are import and export |
| Parts of the file nobody touched survive a save byte for byte | ✓ | — | — |
Opens .xlsx, .xls | Converted first, by LibreOffice on a node that has it | ✓ natively | ✓ on import |
Saves .xlsx or CSV | Exported through LibreOffice | ✓ | ✓ as a download |
| Print, or save as PDF | ✓ | ✓ | ✓ |
| Print area, and a header row repeated on every page | ✓27 | ✓ | ✓ |
| The grid | |||
| Several sheets — added, renamed, removed, given a tab colour | ✓ | ✓ | ✓ |
| Duplicate a sheet, move one, hide one | ✓ | ✓ | ✓ |
| Rows and columns — insert and delete | ✓18 | ✓ | ✓ |
| Hide and show rows and columns, written into the file | ✓ | ✓ | ✓ |
| Column widths and row heights | ✓ | ✓ dragged or an exact number | ✓ dragged or an exact number |
| Merge and unmerge cells | ✓ | ✓ | ✓ |
| Freeze rows and columns | ✓19 | ✓ | ✓ |
| Fill handle — copy, a series, a trend | ✓ | ✓ | ✓ |
| Copy and paste a range, in and out of other spreadsheets | ✓ up to 10,000 cells at a time | ✓ | ✓ |
| Paste special — values only, formats only, transposed | ✓28 | ✓ | ✓ |
| Selecting cells that are not next to each other | ✓ | ✓ | ✓ |
| Zoom | ✓ not written into the file | ✓ | ✓ |
| How large a sheet may be | No limit of its own — the grid draws a window of it | OOXML's own: 1,048,576 rows | 10 million cells |
| Cells | |||
| Bold, italic, underline, strikethrough, size, colour, highlight | ✓ | ✓ | ✓ |
| Fill and borders | ✓ | ✓ | ✓ |
| Alignment across the cell, and up and down it | ✓ | ✓ | ✓ |
| Text that runs on over several lines | ✓ the row is fitted when you ask20 | ✓ | ✓ |
| Number formats — decimals, thousands, currency, dates, per cent | ✓ | ✓ | ✓ |
| A typed date becomes a date | Year first always; any other order only where the cell's format states it32 | ✓ from the locale | ✓ from the locale |
| Making a value stay text — a leading apostrophe | ✓ | ✓ | ✓ |
A format written as a pattern — #,##0.00;[RED]-#,##0.00 | ✓ numbers and colours, not dates33 | ✓ | ✓ |
| Separators follow the document's locale | ✓21 | ✓ | ✓ |
| Named cell styles — Good, Bad, Neutral | ✓ | ✓ | — no style gallery |
| Format painter | ✓ | ✓ | ✓ |
| Rotated text in a cell | ✓ | ✓ | ✓ |
| Formulas | |||
| Functions | 11117 | 450+ | ≈500 |
| Where the arithmetic happens | The daemon on your own machine | The Docs server | Google's |
| A formula it does not understand | Keeps the value the file came with, and names the function | #NAME? | #NAME? |
| When the answer appears | About a third of a second after the last keystroke22 | ✓ as you type | ✓ as you type |
| References follow rows and columns that move | ✓ | ✓ | ✓ |
| References to another sheet | ✓ | ✓ | ✓ |
| References to another file | ✓ a file beside this one, in the same vault34 | ✓ external links | ✓ IMPORTRANGE |
| Named ranges | ✓ | ✓ | ✓ and named functions |
| Array formulas | ✓35 | ✓ | ✓ |
| The formula bar suggests functions, with the signature | ✓ | ✓ | ✓ |
| Clicking a cell puts its address into the formula | ✓ | ✓ | ✓ |
F4 to fix a reference — B2, $B$2, B$2, $B2 | ✓ | ✓ | ✓ |
| The sum, average and count of what is selected | ✓ | ✓ | ✓ |
| Making sense of the data | |||
| Sort by a column, whole rows | ✓ | ✓ | ✓ |
| Sort by several columns | ✓ | ✓ | ✓ |
| Filter a column by its values | ✓ | ✓ | ✓ |
| The filter survives closing the file | ✓23 | ✓ | ✓ |
| A dropdown list in a cell | ✓ a list you type, offered rather than enforced | ✓ | ✓ also from a range |
| Other validation rules — a number range, a date, a length, a formula | ✓ offered rather than enforced29 | ✓ | ✓ |
| Comments on cells | ✓ | ✓ | ✓ threaded |
| Conditional formatting — a colour decided by a test | ✓ | ✓ | ✓ |
| Colour scales | ✓ | ✓ | ✓ |
| Data bars and icon sets | — read and left alone | ✓ | — |
| Pivot tables | ✓ one row, one column and one data field36 | ✓ | ✓ |
| Slicers | The pivot’s page field37 | ✓ | ✓ |
| Remove duplicates, split text into columns | ✓ | ✓ | ✓ |
| Protecting a sheet or a range | ✓ honoured here, not enforced24 | ✓ | ✓ |
| Macros or scripting | — | ✓ JavaScript macros | ✓ Apps Script |
| Charts and pictures | |||
| A chart already in the file is drawn | ✓ | ✓ | ✓ |
| Changing one — kind, title, legend, stacking, series colours | ✓ | ✓ | ✓ |
| Point markers — shape, size | ✓ | ✓ | ✓ |
| Axes — a pinned minimum and maximum, line colour and thickness, label size and colour | ✓30 | ✓ | ✓ |
| Moving and resizing a chart on the sheet | ✓ | ✓ | ✓ |
| Making a new chart | ✓25 | ✓ | ✓ |
| Removing one | ✓ | ✓ | ✓ |
| Kinds drawn | Six — columns, bars, line, area, pie, points (XY). A line is straight, smoothed or stepped | Many | About thirty |
| The chart follows a typed number without a save | ✓ | ✓ | ✓ |
| Where the chart sits | On the sheet, over the cells | Floating over the cells | Floating over the cells |
| Sparklines | — | ✓ | ✓ the SPARKLINE function |
| Pictures on a sheet | ✓ | ✓ | ✓ |
| Handwriting on a sheet | ✓31 | — | — |
| Shapes and text boxes | — | ✓ | ✓ |
| Working together | |||
| Real-time co-editing | ✓26 | ✓ through Docs | ✓ through Google |
| Both edit offline, and both survive | ✓ | — not merged; the sync client leaves a conflict copy | Through the offline extension, set up in advance |
| Version history | ✓ | ✓ | ✓ |
| Ask an AI about a range | ✓ | ✓ a plugin, with your own key | ✓ Gemini |
| Send a range into a chat as a table | ✓ | — | — |
Notes on the spreadsheet table
- Arithmetic, comparison, text, ranges, and the functions those documents
actually contain:
SUM,AVERAGE,MIN/MAX,IF,VLOOKUPandHLOOKUP,INDEX/MATCH,SUMIF/COUNTIF/AVERAGEIFand their plural forms,IFERROR, the text and rounding families, and a small set for fitting a line through numbers. Since: the money functions —FV,PV,PMT,RATE,NPER,NPV,IRR, which are one equation solved five ways rather than five formulas that can disagree; the mathematics a sheet is expected to have,POWERthrough the trigonometric set; the descriptive statistics —STDEVandVARin both their sample and population forms,CORREL,PERCENTILE,QUARTILE,MODE,LARGE,SMALL,RANK; and the date arithmetic that is not a number of days —EDATE,EOMONTH,DATEDIF,WORKDAYandNETWORKDAYS, with a clock beside them. The posture matters more than the count: a function nobody has implemented names itself, the formula is kept verbatim, the file's own value is shown, and the cell is reported as not recalculated. Nothing is guessed at, so the list can grow one function at a time without any document being wrong in the meantime — and two absences are a decision rather than a queue.WORKDAY.INTLandNETWORKDAYS.INTLare not offered because the weekend here is Saturday and Sunday, and the countries where it is not deserve better than a name that quietly gets them wrong.LINESTwas the other, and it is here now: its answer is a block of cells rather than one, which is what the array formulas were needed for. It gives the first two of its ten outputs — the slope and the intercept — because a name that answers two of the ten a caller asked for is worse than one that answers the two everybody uses, andSLOPE,INTERCEPTandRSQare the scalar way to the same numbers. - Both axes. A column has no identity in ODF — it is a width declaration and nothing else — so where a column went is read off the cells that moved with it, and a sheet whose rows disagree about that is left alone rather than half-corrected.
- In
settings.xml, where ODF keeps it, so other spreadsheets honour it on open. Checked against a spreadsheet a desktop LibreOffice actually froze, in both directions: that file reads here as the freeze it is, and freezing a file that has no view settings at all produces the same six entries LibreOffice writes, with the same types and numbers. It had to be a file somebody saved rather than a conversion, because headless LibreOffice has no view and so neither writes view settings nor reads them. - Wrapping does not make the row taller by itself. Every row is the height the file gives it, which is what lets the grid draw a window of a large sheet instead of the whole thing. Fit to what is in it, on the row header's menu, makes a row as tall as its tallest cell — wrapped lines and turned text included — and only ever taller, so a row somebody made deliberately roomy is left alone. Turning text in a cell fits its row with it, once, and it can still be dragged afterwards.
- A Russian document reads
1 234,50and a German one1.234,50— with a no-break space in the first, which is the detail nobody guesses right. The table of fifteen locales was taken from LibreOffice's own "as shown" export rather than from a memory of CLDR. - The other two evaluate in the browser as well as on the server. Here there is one implementation, in the daemon, because a second one in the browser would be a second set of answers to the same question — in the one place where a disagreement does not look like one, since a wrong total looks exactly like a right one. So the answer arrives on a round trip a third of a second after the last keystroke: the same recalculation, in the same place, with nothing written and no version made.
- Both halves are in the file: the rows a filter hides carry
table:visibility="filter", and the filter itself is atable:database-range, so another spreadsheet draws its own filter buttons over the block. Show all rows gives back exactly the rows the filter took — it does not undo what somebody hid on purpose an hour earlier. The translation is worth knowing: a filter here holds the values it hides and ODF holds a positive condition, so "hide South" is written as "everything that is not South", measured to come back out of LibreOffice hiding exactly that. A filter built in another program — a comparison, a nested or — comes back as hidden rows without its list of ticks, because reading half of one would be worse than saying so. - A lock, not a permission, and the editor never says otherwise. The
key ODF writes beside
table:protectedis a digest of a password: nothing is encrypted, every cell is in plain sight in the file, and deleting one attribute takes the protection off. So a protected sheet refuses edits here and no password is offered — one that cannot be enforced would tell the author their sheet is protected from people when it is protected from accidents. A few cells can be left open to fill in, which is what most protected sheets are for. Somebody who should not be able to change a sheet should not be in the vault: that boundary is the vault's, and it is real. - Select the cells, press Chart, pick a kind. What decides whether the chart is right is not the dialog but the reading of the block — which row names the series, which column names the points — so that is guessed from the cells, said in a sentence, and can be overruled. The preview is the real drawing from the real numbers. The chart then sits on the sheet over the cells, where every other spreadsheet puts one; clicking it brings up its controls.
- Two live nodes, two browsers, and the same cell typed into from both sides: one value survives, whole, and the other does not appear anywhere it was not meant to. Getting there took rebuilding how a spreadsheet merges — a cell is a slot at an address, not a paragraph two people extend — and the editor that loses one is told which value went, with a button to put it back. What remains last-writer-wins is a structural edit made at the same moment as somebody's typing: inserting a row while a colleague fills one can cost one of the two rows.
- Both are invisible in the document: a print range is not a style, not a
cell property, and has no shape at all in
.xlsxor CSV, so the only honest test is to print. A word in a corner outside the range, a PDF from headless LibreOffice, and the word has to be gone. The repeated header row is asked the same way — is it at the top of page two. - A shift will not do it: a formula one row below its total has to end up
one column to the right of it, so the row and column of every relative
reference swap. A reference written with a
$is left pointing where it pointed, both halves or neither, which is Excel's answer too. - Every spelling was built by hand and converted to
.xlsxto see what LibreOffice made of it, and three of the first six came out meaning something else —cell-content-is-between(1;10)reads as nothing where(1,10)reads as a range, and<>comes back as<with the>left inside the number. So there is no "is not" among the operators. The custom formula was left out for the same reason and the reason was wrong: asked of Calc directly rather than through a conversion, LibreOffice writesof:is-true-formula(…)and reads its own file back unchanged. What it does not survive is the journey to.xlsx, and that is equally true of LibreOffice's own file. None of the rules is enforced as you type — the file's rule is what every other spreadsheet enforces on open, and a second implementation here would enforce the list while leaving a number range unchecked. - The number format on an axis names a style in the chart's own sub-document, exactly the way a cell names one — the same parser and the same writer, and the picker offers the sheet's own list because it is the same question about the same numbers. What LibreOffice would not keep is the stroke written beside an axis colour: it drops it and keeps the colour, so the colour alone is what says there is a line.
- The same pad the document editor uses, anchored in a cell instead of standing in a line of text. A note is a picture with the strokes inside it, so it moves, resizes and travels like any other picture, and opening it again gives back the strokes rather than a flat image. It is fitted to the width a chart gets rather than dropped at the size it was drawn — the pad is as wide as the window allows, and a sheet has no column width to normalise against afterwards the way a page does.
-
2026-08-25is one date everywhere and is always read as one.03/04/2026is the third of April or the fourth of March depending on who is reading it, and a file here is read by people in different countries — so it stays text unless the cell's own number format says which order it is in, and then it is read that way. No locale is consulted anywhere, which is also why a cell already formattedDD.MM.YYYYcan be edited and stays a date: the format that wrote the text is the format that reads it back. -
0#,.for the number,%,@for the text part,[RED]and ODF's seven other colour names, quoted literals, and up to four parts separated by;— positive, negative, zero and text. Not dates and times, which have a pattern language of their own in the same panel; not scientific notation or fractions; not the[>=100]thresholds. The pattern is not in the file at all: ODF compiles one into a family of data styles joined bystyle:map, so it is decompiled to show you and compiled again only when you change it — a format you looked at and did not touch is written back as the styles it already was. - The reference in the file names an absolute path, and LibreOffice
writes it absolute even when the target sits in the same folder. On a
mesh that path names a machine, so only the file's own name is taken
out of it and the document looked for is the one of that name in the
same folder of the same vault — which is the resolution that survives
the file being opened on another node. It is read for its stored
values rather than recalculated, the way every spreadsheet reads a
link. A file that cannot be reached leaves the cell showing the number
it last had, which is what the file already carried and what every
other program shows too. Type it as
='rates.ods'#$Rates.A1; the fullfile:///form LibreOffice writes is read as well. =A1:A5*2in five cells, entered with Ctrl+Shift+Enter. A range contributes its own cells, a scalar contributes itself everywhere, and a range shorter than the block repeats its last row or column — so=A1:A5*B1is each of those times that.SUM(A1:A3*B1:B3)works for the same reason. Part of a block cannot be typed into, which is what every spreadsheet says and what stops the file claiming two different things about one set of numbers.LINESTis the one function whose own answer is a block.- Row, column, data and page fields; sum, count, average, max and min. One of each field at a time: several data fields at once, subtotals inside the body, grouping by date or by range, and calculated fields are each a different table rather than more of this one. The answers are worked out in the daemon beside the formulas — one implementation, one set of answers — and the cells they land in refuse to be typed into, because the next rebuild would write over the edit without a word. Pivot on the Data tab builds one and, on a cell inside a table, changes that one instead. Where it goes is asked once: a table can be removed, which takes its answers with it, but not moved, because moving one means clearing the block of cells it left behind. It will not go on top of the block it summarises — a table grows down and to the right, so it goes below that block or to the right of it — and the daemon refuses the same thing at every rebuild, because a table that was clear of its source can grow into it.
- There is no slicer in ODF and none in LibreOffice Calc. An Excel
slicer is an
.xlsxextension and survives the conversion in neither direction, so building one would mean a control only this editor understands, invisible everywhere else. What ODF has instead is the pivot's page field — click the value at the top of the table and the whole table follows — and it renders as cells in every reader. That is what is built, with a picker on the cell holding the value.
What it does not do
- It does not edit
.docxin place. ODF is the format; foreign files are converted in, and exported back out as new files. - It does not run without LibreOffice for foreign formats. Native
ODF documents need nothing; a
.docxneeds a node with LibreOffice somewhere in the network. - It is not a spreadsheet's analysis suite. Pivot tables take one row, one column and one data field; there are no subtotals inside the body, no grouping by date or range, no calculated fields, no sparklines and no macros. What is there is the shape a budget, a tracker or a model needs.
- It is not Secure View. A watermark — on the page or on an exported PDF — marks the copy you hand over; it does not stop the recipient saving, printing or forwarding it. Preventing that needs a server that renders documents the viewer never receives, and MeshHold decrypts on the client by design.
- Paper of two sizes is not drawn at two sizes. A document that turns
landscape in the middle is written, paginated and printed correctly, and
the editor draws it on one sheet as wide as its widest page with the
narrower pages inset. Measured before it was decided: see
web/spike-paper.html. - Page-wide columns are not drawn side by side. The text is set at one column's width, so the line breaks and the page count are the ones you will get on paper, and the columns are drawn one under the other with a mark where each ends. Printing and every other application show them side by side. Columns across selected paragraphs — a region — are drawn side by side here too.
- The equation editor takes a subset of LaTeX. Letters and numbers,
the arithmetic,
^and_, fractions, roots, upright text, the Greek letters and the common operators and functions. Anything outside it is refused by name rather than half-translated.