Univer puts a spreadsheet, document editor and slides in your app

42 minutes ago

A real spreadsheet, running inside somebody else's web app. This one is built with Univer, an open source kit you drop into your own product. The same kit also draws documents and slide decks.

Ask

Ask about this presentation

Answers are generated from this presentation.

Chapters

  1. 0:00Univer · an open source office kit you build into your own app
  2. 0:11A workbook, a document and a slide deck are the same kind of object
  3. 0:33Three answers, and a correction to the pitch
  4. 0:51Three hard problems sit under every grid on a web page
  5. 1:12One door in, and three lines that say which class handles which type
  6. 1:45One runtime under all three, and only one of them is free
  7. 2:04All six types run. One of them is built on the free packages.
  8. 2:43Two kinds of change, and only one crosses into your file
  9. 3:27Four fields carry a batch of saved changes
  10. 4:10A slide takes a different route to the same engine
  11. 4:37Twenty packages ship twice, once without a screen
  12. 5:05The free licence buys the engines. The multiplayer layer is the paid product.
  13. 5:32Open does not mean equally finished
  14. 6:01The hard half is the free half
  15. 6:23Google Sheets can do this today, on Google’s servers
  16. 6:54Where Univer sits among the embeddable spreadsheets
  17. 7:18Sixteen lines to a workbook, or sixty-one
  18. 7:40Who should install Univer this weekend
  19. 8:04Apache-2.0, TypeScript, browser and server
  20. 8:38What is the last app you used that quietly turned into a spreadsheet?
Show transcript

Univer · an open source office kit you build into your own app

the project’s own showcase

Univer

The open source office kit: sheets, docs and slides in one runtime you build into your own app
TypeScriptApache-2.0, free to ship commerciallybrowser and server
spreadsheetdocumentslide deck

A real spreadsheet, running inside somebody else's web app. This one is built with Univer, an open source kit you drop into your own product. The same kit also draws documents and slide decks.

A workbook, a document and a slide deck are the same kind of object

One codebase, and a workbook, a document and a slide deck are the same kind of object in it

The Univer spreadsheet showcase, formula bar and product lookup grid
the project’s own showcase
spreadsheetdocument editorslide editor
one saved state
one revision number
under all three

Univer comes from a team called dream-num, and you build it into your own product. Here is the spreadsheet it gives you, running in a browser tab, looking up prices against a product table. Your users get a real spreadsheet, a real document editor and a real slide editor, all three inside your app. And underneath all three sits one kind of object, with a saved state and a number that says which version of the file you are holding.

Three answers, and a correction to the pitch

The Univer spreadsheet showcase, dimmed behind the slide copy
1
What a workbook and a slide deck share in this codebase
2
Which edits reach your saved file, and which never do
3
Where the free licence stops

By the end you'll know what a workbook and a slide deck have in common inside this codebase, and which edits are allowed to touch your saved file. And I'll show you where the free licence actually stops, because the pitch needs a correction. Six document types run in the project's showcase, and one of them runs entirely on the free packages.

Three hard problems sit under every grid on a web page

Two people typing in one cell
An undo that knows what to undo
A formula that calculates with no browser in sight
Solve all three once, underneath, and every editor inherits the answer

Putting a grid on a web page is a solved problem. Three things after that are hard. Two people typing in one cell without clobbering each other. An undo that knows exactly what to undo. And a formula that still calculates when there is no browser anywhere, on a server. Univer's answer is to solve those three once, underneath, and let the spreadsheet, the document editor and the slide editor all inherit the answer.

One door in, and three lines that say which class handles which type

the whole registry, shortened for the slide
createUnit(type, data)
registerCtorForType(UNIVER_SHEET, Workbook)registerCtorForType(UNIVER_SHEET, Workbook)
registerCtorForType(UNIVER_DOC, DocumentDataModel)registerCtorForType(UNIVER_DOC, DocumentDataModel)
registerCtorForType(UNIVER_SLIDE, SlideDataModel)registerCtorForType(UNIVER_SLIDE, SlideDataModel)
core · univer.ts on the project’s dev branch
every unit carries a saved state
every unit carries a revision number
one base class under all three

The door in is eight lines of real code. You ask the runtime to create a unit, and you hand it a type and some data. A unit is one open thing with an id and a saved state, whether that thing is a workbook, a document or a slide deck. Three lines say which class handles which type. Sheet gets Workbook. Document gets DocumentDataModel. Slide gets SlideDataModel. All three extend one base class, and that base class is where the saved state and the revision number live. A revision number is a counter that lets two copies of one file work out which copy is behind. So a workbook and a slide deck differ by one value in a list of type names.

One runtime under all three, and only one of them is free

The Univer spreadsheet showcase with a product lookup grid
open packages
The Univer document editor showcase with a decision register table
open editor, paid tables and charts
The Univer slide editor showcase, watermarked Univer Office with a License Required line
paid slide packages
the project’s own showcase

The project runs all of this in a public showcase, and I opened three of them. The spreadsheet runs on the open packages. The document editor is open too, and its tables and its charts come from the paid plugins. The slide editor is the paid slide package, watermark and all. Three separate editors, one runtime underneath every one of them.

All six types run. One of them is built on the free packages.

spreadsheets
open packages
documents
open, paid tables and charts
slides
packages with pro in the name
PDFs
packages with pro in the name
boards
packages with pro in the name
relational tables
packages with pro in the name
from the project’s own showcase
547 demos, all six types
core · presets · preset-sheets-core
three types registered in the open core
PDFs still listed as coming soon
slides
PDFs
boards
relational tables

The repo describes six document types in one runtime. Spreadsheets, documents, slides, boards, relational tables and PDFs. Go to the showcase and all six of them run, across five hundred and forty-seven demos. Then I opened what each demo actually loads. The spreadsheet pulls in three packages, and all three are free and Apache licensed. The slide deck, the PDF, the board and the relational table each pull in packages with pro in the name, and the slide demo is stamped, License Required. The open core registers three document types, and the project's own front page still lists PDFs as coming soon. Six types in the product, one type fully inside the free licence.

Two kinds of change, and only one crosses into your file

a command
a saved change
a screen change
what you asked the app to do
goes into your saved file
never enters your saved file
your saved file ends here
“the smallest unit of conflict resolution”
the repo’s own comment
scroll positionsidebar open
delete the row
delete the row
put the row back, for undo
set the cell contents
3 commands · 17 saved changes · 0 screen changes
our run, no screen attached

Every change in Univer carries a label, and that label decides whether the change reaches your saved file. A saved change goes into the file. The repo's own comment calls a saved change the smallest unit of conflict resolution, and what that means is the smallest piece the software will argue about when two people edit one cell at once. A screen change never enters the file. Where you scrolled to, whether the sidebar is open. Those are real changes to what you see, and the saved file never hears about them. And one action can make several saved changes. Delete a row, and that single action produces the saved change for the delete, the saved change that puts the row back for undo, and the saved change for the cell contents. I made three edits with no screen attached at all, and got three commands, seventeen saved changes, and zero screen changes.

Four fields carry a batch of saved changes

the wire format, fields elided
interface IChangeset {
unitID: string unitID: string
baseRev: number baseRev: number
revision: number revision: number
mutations: IMutation[] mutations: IMutation[]
} interface IMutation { id: string data: string // serialized params }
the free packages, sending to a background worker
if (type === CommandType.MUTATION && ...) {if (type === CommandType.MUTATION && ...) {
// only sync mutations to the worker thread }
your keyboarda serversoftware acting for you
revision numbers and merging two edits
the paid collaboration server
in the free packages the counter stayed at 1
our run

A saved change carries only plain data, small enough to write down and send. The free code already does exactly that. One line forwards saved changes to a background worker, and only saved changes. The format it sends is in the repo too. A unit id, the revision it started from, the revision it produces, and a list of saved changes whose contents are written out as text. So an edit from your keyboard, from a server, or from a piece of software acting for you is the same kind of thing on the wire. The part that hands out revision numbers and merges two people's edits is the collaboration server, and the team sells that one separately. In the free packages the revision counter never moves. Mine stayed at one.

A slide takes a different route to the same engine

Engine
Sceneone per open thing
BaseObjecteverything drawn in a scene
RenderComponent
SceneViewer
SheetComponent
DocComponent
Slideone scene per page
SheetComponent
DocComponent
Slideone scene per page
one draw call between them
a document inside a cell
a spreadsheet inside a document

One drawing engine draws every document type. Each open thing gets a scene, and everything inside a scene is the same base object. The spreadsheet and the document editor go further and share one component class, with one draw call between them. A slide is a viewer that holds one scene per page, on that same engine. And I like what that buys you. A document can sit inside a cell, and a spreadsheet can sit inside a document, with no second renderer to negotiate with.

Twenty packages ship twice, once without a screen

logic half
screen half
sheets
sheets-ui
sheets-filter
sheets-filter-ui
docs-toc
docs-toc-ui
slides
slides-ui
thread-comment
thread-comment-ui
… 15 more pairs
… 15 more pairs
20 pairs · 40 of 60 packages
“support of Node.js is at the same priority as browsers”
the project’s contributor guide
no browser · no page
=SUM(A1:A2)*10
50
our run

You can read this project's core rule straight off its folder names. Sixty packages, and forty of them sit in twenty pairs, a logic half and a screen half. The filter is one package and the filter's menu is another. The table of contents, the same. The contributor guide states why. Running with no screen, on a server with no browser, is the same priority as running in the browser. So I ran the logic half on a server runtime with no browser and no page at all, put a sum formula into a cell, and got fifty back.

The free licence buys the engines. The multiplayer layer is the paid product.

In the Apache licence
core · plugin system
rendering engine
formula engine
themes and adapters
In Univer Pro
real time collaboration
real time collaboration
edit history
edit history
import and export
import and export
printing
printing
charts and pivot tables
charts and pivot tables
calculation on a server
calculation on a server
“OSS documentation should not imply that Pro-only capabilities are available in public packages”
the project’s own README
and they published that rule themselves

What the free licence gives you is the core, the engines and the plugin set. Real time collaboration, edit history, import and export, printing, charts, pivot tables and calculation on a server are Univer Pro, a separate commercial product you pay for. The team also wrote a boundary rule into its own documentation, saying the open source docs should not imply that paid capabilities are available in the public packages. They drew the line, and then they published it. I have not seen many projects do that.

Open does not mean equally finished

documents
155
spreadsheets
22
slides
2
source files in the drawing engine
“sheets are the most mature product surface today”
“presentation data model and UI packages under active development”
the project’s front page
Under the project’s own stability policy, that makes the open slides interface experimental

The three open surfaces are at very different stages. Inside the drawing engine, the slides folder holds two source files. The documents folder holds a hundred and fifty-five. The project says the same thing in words. Spreadsheets are its most mature surface today, and the presentation model and its interface packages are under active development. Under the project's own stability policy, that second phrase makes the open slides interface experimental. I would not build a presentation product on this one today.

The hard half is the free half

Three Univer workbooks side by side on one page, each with its own toolbar and sheet tabs
three workbooks on one page, from the project’s docs
object modelformula enginedrawing surfaceedit bus
multiplayer and file formats, when you pay

Both catches land in the same place if you are the one building. You are getting the part that is genuinely hard to build. The object model, the formula engine, the drawing surface and the edit bus, under a licence that lets you ship all of it in a commercial product. Run several workbooks on one page if you want, and the project's own docs show three at once. What you pay for, when you pay, is the multiplayer layer and the file format compatibility.

Google Sheets can do this today, on Google’s servers

Google Sheets
Univer
on Google’s servers
on Google’s servers
in your page and your database
in your page and your database
inside Google’s account system
inside Google’s account system
inside yours
inside yours
edits cross the network to Google
edits cross the network to Google
you route the edits
you route the edits
Handsontable and AG Grid hand you the grid

Google Sheets already does all of this, and Google publishes a way for your own app to read and write a sheet, which you could wire up this afternoon. That is true, and the difference is where the document lives. With Google Sheets the document lives on Google's servers, inside Google's account system, and your app talks to it across the network. With Univer the document lives in your page and in your own database, and you decide where the edits get routed. I would rather have the document in my own storage. Handsontable and AG Grid hand you the grid. Univer is going after the whole document.

Where Univer sits among the embeddable spreadsheets

Handsontable with HyperFormula
the embeddable grid with a real formula engine
AG Grid
the enterprise data grid
Grist
an open source relational spreadsheet you host as an app
Univer
sheets, docs and slides on one object model
Luckysheet, same team, archived
“Luckysheet upgraded to Univer”
that repo’s own description

Handsontable, paired with HyperFormula, is the embeddable grid with a real formula engine behind it. AG Grid is the enterprise data grid. Grist is an open source relational spreadsheet, and you host it as an app. Univer is the one going after all three document types with one object model. And it is the successor to Luckysheet, from the same team. That repo is archived now, and its description reads, Luckysheet upgraded to Univer.

Sixteen lines to a workbook, or sixty-one

the short path, shortened for the slide
pnpm add @univerjs/presets @univerjs/preset-sheets-core createUniver({ presets: [UniverSheetsCorePreset()] })
2 packages · 1 call · 16 lines
the long path, shortened for the slide
univer.registerPlugin(UniverRenderEnginePlugin) univer.registerPlugin(UniverFormulaEnginePlugin) univer.registerPlugin(UniverUIPlugin, { container }) … eight more registerPlugin calls
13 packages · 11 calls · 61 lines
Both paths are in the quick start

Two ways in, and they are very different lengths. The short path is two packages and one call. Sixteen lines of code, and a workbook appears. The long path, where you pick every piece yourself, is thirteen packages, eleven registration calls and sixty-one lines before an empty workbook shows up. Both paths are in the quick start. I would start short and take the long one the day you actually need it.

Who should install Univer this weekend

Install now
your product needs a real spreadsheet in it and you want the document in your own storage
Wait
you need file import and export, or two cursors in one document, on day one
Skip
you want a grid to display rows in

I would reach for Univer if your product needs a real spreadsheet inside it and you want the document in your own storage. And I would start with sheets, not slides. I would wait if you need file import and export, or two cursors in one document on day one, because both of those sit in the paid tier. And I would skip it if what you want is a grid to display rows in. That is a much smaller job than this one, and Handsontable or AG Grid will do it.

Apache-2.0, TypeScript, browser and server

Licence
Apache-2.0, free to ship commercially
Language
TypeScript
Browsers
current Chrome, Edge, Firefox, Safari and Electron
Server
Node on a server, no browser needed
an early build, going since 2022, with a 1.0 release candidate out for testing

Apache-2.0, so you can ship it inside a product you sell. It is written in TypeScript, the typed flavour of the language browsers already run. It works in current Chrome, Edge, Firefox and Safari, in Electron, which is the wrapper that turns a web app into a desktop app, and on a server with no browser at all. It is an early build, from a codebase that has been going since 2022, with a 1.0 release candidate out for testing right now and new code landing today. The default install is still the early line, and the release candidate is the one I would watch.

What is the last app you used that quietly turned into a spreadsheet?

The Univer spreadsheet showcase, dimmed behind the closing question
What is the last app you used that quietly turned into a spreadsheet?
dream-num / univer
github.com/dream-num/univer
New repo tomorrow

What is the last app you used that quietly turned into a spreadsheet? Mine was a project tracker that grew formulas, and then grew a chart. The repo is dream-num slash univer, on GitHub. New repo tomorrow.