Excel Formulas in a Web Editor
Most rich-text editors can draw a table. Very few can calculate one.
That sounds like a small thing until you ship a product where people write real business documents: invoices, quotes, budget reports, KPI summaries, data-entry forms. Change a number and someone expects the total to change with it. In a normal web editor it doesn't. The table is just markup, so the arithmetic has to live somewhere else, whether that's a spreadsheet, your backend, or a second component stapled onto the page.
This post is about doing the math inside the editor instead, and why that turns out to be something the other editors can't really do.
When a table is just HTML
In CKEditor, TinyMCE, and Froala, a table cell holds HTML. It can store text, styling, sometimes an image. It cannot store a formula. There's no calculation engine and no recalculation step. If a cell reads 533, that's because a person or your backend wrote the string 533. Change the inputs and nothing downstream moves.
How a table cell behaves: inert markup that only stores text, versus a cell that holds a formula the engine evaluates and keeps up to date.
So when a document needs to add things up, teams fall back on one of two workarounds, and both cost something:
- Round-trip through Excel. Export, calculate in a spreadsheet, import again. It's slow, easy to get wrong, and it breaks the "edit it right here" promise that made you embed an editor in the first place.
- Embed a separate spreadsheet or data-grid SDK. Now you have a second component, a second vendor, another line on the license, and a second data model that lives outside the editor's selection, undo stack, and export. Two things to maintain, kept in sync by hand.
Either way, what should be one editing surface becomes two tools wired together, and users can feel the seam.
A cell that holds a formula
SynapEditor does it the other way. The table engine inside the editor evaluates formulas itself. Type = in a cell to enter formula mode, write something like =SUM(B2:E2), =VLOOKUP(...), or a nested INDEX/MATCH, and it computes. There are more than 290 Excel functions available, and they recalculate in the browser the moment a value changes.
A Total cell in formula mode showing
=SUM(B3:C3), with the rest of the table's values computed alongside it. Change an input and it recalculates instantly.
The formula isn't a widget sitting on top of the page. It belongs to the same document as the text and headings around it: one selection model, one undo history, one save format, one export path. The number and the paragraph next to it are part of the same thing.
You turn it on with editor config, not a separate integration. The table demo uses a deliberately small toolbar:
// SynapEditor configuration (license.config.js supplies the license)
var config = Object.assign(synapEditorConfig, {
'editor.lang': 'en',
'editor.toolbar': [
'new', 'table'
],
'editor.menu.show': false
});
var editor = new SynapEditor('synapEditor', config, initialHtml);
That's all of it. The editor core loads from the CDN, and your page supplies the license and a container element.
What 290+ functions cover
"290+" is an easy number to print on a feature page, so it's worth saying what it covers. The library includes the families that finance and operations people use constantly:
- Aggregation and math:
SUM,AVERAGE,MIN,MAX,COUNT,ROUND,SUMIF. - Lookups:
VLOOKUP,HLOOKUP, and nestedINDEX/MATCHfor the cases one lookup can't handle. - Logical:
IF,AND,OR,IFERROR, so a cell can branch instead of holding a fixed value. - Text and date:
CONCAT,LEFT/RIGHT/MID,TEXT, plus date math for labels and reporting periods.
The number itself isn't what counts. What matters is that the everyday, load-bearing functions are there, so a real report or form doesn't hit a wall on the first calculation and send everyone back to Excel.
How authors address cells
Before the worked examples, it helps to be precise about how someone actually writes one of these formulas, because the addressing is plain Excel-style A1 notation. A column is a letter, a row is a number, and a single cell is the letter plus the number: B2 is column B, row 2. That's the same scheme your users already know from any spreadsheet, so there's nothing new to teach them.
Ranges come in two shapes, and the budget table uses both. A row range like B2:E2 walks across one row, from column B to column E on row 2. That's how the Total column adds up a single quarter-by-quarter row: =SUM(B2:E2). A column range like B2:B4 walks down one column, from row 2 to row 4 in column B. That's how the Total row adds up a single quarter down all of its line rows: =SUM(B2:B4). Same SUM, different axis, and the colon is just "everything from here to there." Once a developer sees those two forms, most of the budget reads itself: rows sum across, totals sum down, and a single cell reference like B2 points at one value.
Walkthrough: a budget that adds itself up
Here's a quarterly budget written directly in SynapEditor. Each row holds quarterly figures. The Total column uses =SUM(...) formulas, and the Total row adds up each quarter. Change any quarter and the totals update in place, with no export and no second tool.
A sales table living inside the editor. The Total row and column are computed by live
=SUM formulas; the YoY and Status columns add percentage number formats and conditional formatting. Change a number and the totals recalculate.
The way you think about the table shifts here. It stops being "a table in a document" and becomes "a small spreadsheet that happens to live in a document." For an embedded editor, that's the gap between a feature you have to ask a third party for and one you already shipped.
Walkthrough: a quote that does its own arithmetic
The budget shows aggregation. A quote shows the thing that actually trips people up, which is a chain of cells that depend on each other. Picture an account manager at a B2B SaaS building a quote inside the editor. The line-item table looks like this, with quantity in column B, unit price in column C, and a line total in column D:
| Row | Item | Qty (B) | Unit price (C) | Line total (D) |
|---|---|---|---|---|
| 2 | Onboarding | 2 | 500 | =B2*C2 → 1000 |
| 3 | License seats | 10 | 120 | =B3*C3 → 1200 |
| 4 | Support plan | 1 | 800 | =B4*C4 → 800 |
Each line total is its own small formula: =B2*C2 multiplies quantity by unit price for that row. Below the table, three more cells finish the math:
- Subtotal:
=SUM(D2:D4), a column range down the line-total column, giving 3000. - Tax:
=subtotal*0.1, ten percent of the subtotal, giving 300. - Grand total: subtotal plus tax, giving 3300.
Now the part that matters for an integrating developer: the dependency chain. Say the manager bumps the license seats from 10 to 25. They change one cell, B3. The engine doesn't recompute the whole document blindly, and it doesn't make the manager re-enter anything. The value in B3 changed, so D3 (=B3*C3) recalculates to 3000. D3 feeds the subtotal range D2:D4, so the subtotal recalculates to 4800. The subtotal feeds the tax (=subtotal*0.1), so tax becomes 480. Tax and subtotal feed the grand total, so it lands at 5280. One edit, and four downstream cells follow it in order, in the browser, while the manager watches.
A discount behaves the same way. Knock the onboarding unit price in C2 down to 250 and the line total D2 halves to 500, the subtotal drops, tax tracks it, the grand total tracks tax. The author never touches the totals. They touch the inputs, and the document keeps the rest honest. Compare that to a quote that's really a rich-text page where someone typed 3300 by hand and forgot to update it after the discount.
This same shape is everywhere in business documents: invoices with line totals and tax, budget execution sheets, timesheets where hours times rate rolls up to a total, data-entry forms where people enter numbers and read results. The author edits inputs, the engine maintains the derived values, and all of it sits in one surface the manager already knows.
Why the shared document model matters
You could wave this off as "just embed a grid library." But the value isn't the arithmetic by itself. The arithmetic lives in the same model as everything else, and that has concrete consequences when you're the one integrating the editor.
One serialization. When you save, you save once. The formula in D2, the heading above the table, the paragraph of terms below it, and the styling all go into the same document and come back out the same way. There's no "document plus a spreadsheet blob" to store as two artifacts, no second write path, no risk of the prose saving successfully while the calculated table fails to. Your persistence layer sees one object.
One undo stack across prose and formulas. A user fixes a typo in a sentence, then edits the tax formula, then changes a quantity. Ctrl+Z walks back through all of it in the order it happened, because it's all one history. With a bolted-on grid, undo inside the grid is the grid's business and undo in the editor is the editor's business, and they don't share a timeline. Your users hit that wall constantly: they undo, the cursor jumps, and the wrong thing reverts because the action they wanted to undo lived in the other component's stack.
Copy-paste of a mixed region as one unit. Select a block that spans a heading, a paragraph, and the calculated quote table, copy it, and paste it into another document. It comes across as one thing, formulas intact. With two components, a selection that starts in prose and runs into the grid is two selections that you, the integrator, have to detect, stitch, and reassemble, because the browser's native selection doesn't span the component boundary cleanly.
A real .xlsx export that keeps the formula. Because the cell holds an actual formula in the model, exporting to .xlsx writes out =SUM(D2:D4), not the frozen number 3000. Open it in Excel and it's still alive: change an input there and it recalculates. The layout also holds through Word and PDF export (PDF via print or preview). An export pipeline that flattens formulas to their last computed value is the quiet failure mode of most bolted-on setups, and it decides whether your customer gets a deliverable they can keep working in or a dead snapshot.
Each of those is work you don't have to do. You're not writing sync code between two models, not special-casing undo at a boundary, not reassembling cross-component selections, not teaching your export pipeline about a grid it doesn't own.
What "embed a data-grid SDK" actually costs
A separate data-grid or spreadsheet SDK gives you cells that compute. It also sits outside everything the editor manages, and that boundary is where the integration cost hides.
You now have two data models. The editor owns the prose and the surrounding document; the grid owns its cells. Anything that has to be consistent across both, the document's saved state, its version, its "is this dirty" flag, you keep in sync by hand, and every feature you add later has to remember to update both.
You have two undo stacks that break at the component edge. The editor's history doesn't know about edits inside the grid, and the grid's history doesn't know about the paragraph the user just rewrote. There's no single Ctrl+Z that does the obviously-correct thing, and building one means intercepting undo in both components and trying to merge two timelines that were never meant to merge.
Your export pipeline doesn't know about the grid. When you serialize the document for save or export, the grid is an opaque region to the editor. Getting its formulas into the same .xlsx or the same saved document means a separate export path for the grid, then merging the two outputs, and keeping that merge correct as both vendors change their formats.
Selection stops at the component boundary. The grid usually lives in its own iframe or its own component subtree, so a user's selection can't naturally run from a sentence into a calculated cell and back. Copy, paste, formatting, and commands that should span the whole document all have to be specially handled at that seam, and the seam is exactly where users notice the product is really two products.
None of that is a knock on data-grid SDKs. They're good at being spreadsheets. The catch is that bolting one into a document editor means owning the wiring between two systems forever, and that wiring is precisely what an in-document engine doesn't make you write.
Bringing in a real .xlsx
Writing from scratch is half the job. Most teams already have spreadsheets. SynapEditor imports Office documents (.docx, .xlsx, .pptx, .odt) with formatting kept, including formulas, complex tables, and shapes. So an existing budget workbook can come into the document, stay calculable, and go back out without being flattened to dead text. The import-edit-export round-trip is usually where web editors quietly lose the math. Here it's the same engine on both ends, which is why a =SUM(...) that came in from your real .xlsx is still a =SUM(...) when it exports back out.
Why this is hard to copy
This is why it isn't a checkbox comparison. CKEditor, TinyMCE, and Froala don't have a weaker formula engine. They have no formula layer at all. For their users, "calculated tables" means integrating a third-party SDK with its own vendor and its own data path, with everything the previous section described coming along for the ride. SynapEditor calculates inside the document it's already managing.
When you're picking an editor to embed, that difference won't show up in a feature grid. It shows up the first time a customer pastes a real budget and expects it to add up.
Evaluating it for your product
A formula engine is the kind of thing you should test against your own documents before you commit, rather than take on faith from a number on a page. A short checklist:
- Confirm your specific function set. The 290+ list covers the common finance and ops families, but your product may lean on a particular lookup or text function. List the functions your real documents use and check each one is present before you design around it.
- Test the import/export round-trip with your real
.xlsx. Don't test with a toy file. Take an actual workbook your customers send, import it, edit a value, export it back to.xlsx, and open the result in Excel. Confirm the formulas survived as formulas and recalculate, and that the layout holds through Word and PDF export too. - Test copy-paste of a calculated region. Select a block that spans text and a calculated table, copy it, paste it elsewhere, and confirm it arrives as one unit with the formulas intact. This is the behavior that's hardest to fake with a bolted-on grid, so it's the most telling thing to try.
- Confirm recalculation behavior on edit. Change one input in a dependency chain like the quote example and watch the downstream cells update in the browser. Make sure the timing and the result match what your users will expect when they change a quantity or apply a discount.
Where the limits are
A formula engine in a document editor isn't a full spreadsheet application, and it shouldn't act like one. Being clear about that helps the case:
- It's good for totals, derived columns, validation-style calculations, financial and reporting documents, and data-entry forms where people enter numbers and read results, all inside the editing surface.
- When you need giant models, pivot tables, or thousands of interdependent cells, reach for a real spreadsheet app. That's a different product, and that's fine.
It's an in-document formula engine, sized for the documents an editor actually holds. For embedded document use cases, that's the right tool, and it happens to be the part competitors can't match.
How it fits your stack
Because it's part of the editor, there's nothing new to run. No extra service to deploy, no second SDK to license, no separate store to back up. Turn on the table toolbar, let users type =, and the documents your product already stores become calculable. The integration surface is the same new SynapEditor(...) call you already make.
Try it
Drop SynapEditor into a page, turn on the table toolbar, and type = in a cell. If your product makes documents with numbers people care about, the editor can now do the math, with no second tool, no export, and no third-party grid.
→ See the live demos at synapeditor.com