Table Calc

approved

by Benjamin Patterson

Adds formula support to markdown tables. Use =SUM(A1:A5), =AVG(B1:B3), =A1*B1, etc. in any table cell. - This plugin has not been manually reviewed by Obsidian staff.

2 stars616 downloadsUpdated 1mo agoMIT

Table Calc — Obsidian Plugin

Add spreadsheet-style formulas to your markdown tables. Write =SUM(A1:A5), =B1*C1, or =AVERAGE(A1:A3) directly in any table cell and see the results rendered inline — in both Live Preview and Reading view.


Quick Start

Add {{calc}} on the line immediately above your table to opt it into formula evaluation:

{{calc}}
| Item        | Cost | Qty | Total       |
|-------------|------|-----|-------------|
| LLC filing  | 200  | 1   | =B1*C1      |
| Dev account | 99   | 1   | =B2*C2      |
| Accountant  | 250  | 1   | =B3*C3      |
| **Total**   |      |     | =SUM(D1:D3) |

The plugin hides the {{calc}} marker and adds column letters (A, B, C…) above the header and row numbers on the left so you always know which cell to reference.

Tables without a {{calc}} marker are left completely untouched.


Column and Row Reference

LabelMeaning
A1Row 1, first column
B2Row 2, second column
A1:A5Range: column A, rows 1 through 5
A1:C32D range: columns A–C, rows 1–3

Supported Formulas

Functions

FormulaDescriptionExample
=SUM(A1:A5)Sum a range=SUM(D1:D3)
=AVERAGE(A1:A5)Average of a range=AVERAGE(B1:B4)
=MEDIAN(A1:A5)Median of a range=MEDIAN(B1:B5)
=MIN(A1:A5)Smallest value=MIN(B1:B10)
=MAX(A1:A5)Largest value=MAX(B1:B10)
=COUNT(A1:A5)Count numeric cells=COUNT(A1:A5)
=COUNTA(A1:A5)Count non-empty cells (numbers or text)=COUNTA(A1:A5)
=PRODUCT(A1:A5)Multiply a range together=PRODUCT(B1:B3)
=STDEV(A1:A5)Sample standard deviation=STDEV(B1:B10)
=VAR(A1:A5)Sample variance=VAR(B1:B10)
=ABS(A1)Absolute value=ABS(A3)
=ROUND(A1, 2)Round to N decimals=ROUND(B1, 2)
=FLOOR(A1)Round down to nearest integer=FLOOR(B1)
=CEILING(A1)Round up to nearest integer=CEILING(B1)
=TRUNC(A1, 2)Truncate to N decimals (no rounding)=TRUNC(B1, 2)
=INT(A1)Round down to integer=INT(B1)
=SIGN(A1)-1, 0, or 1 depending on sign=SIGN(B1)
=SQRT(A1)Square root=SQRT(B1)
=POW(A1, B1) / =POWER(A1, B1)Exponentiation=POW(2, 10)
=MOD(A1, B1)Remainder of division (result takes the sign of the divisor, e.g. MOD(-7,3)2)=MOD(A1, 3)
=EXP(A1)e raised to the power of x=EXP(1)
=LN(A1)Natural logarithm=LN(8)
=LOG(A1) / =LOG(A1, base)Base-10 log (single-arg), or log to a given base=LOG(8, 2)
=LOG10(A1)Base-10 logarithm=LOG10(100)
=PI()The constant π=ROUND(PI(), 2)

Arithmetic

OperatorExample
+=A1+B1
-=A1-B1
*=B1*C1
/=A1/B1
^=A1^2 (exponent)
Grouped=(A1+B1)*C1
Scientific notation=1e3+11001

Mixed

Combine functions and arithmetic freely:

=SUM(A1:A3)*1.1
=ROUND(AVERAGE(B1:B5), 2)
=A1+SUM(B1:B3)

Note: Function arguments must be cell references, ranges, or literal numbers — not inline expressions. Use =ABS(A1) not =ABS(A1-B1).


Error Values

ErrorCause
#ERRInvalid expression, divide by zero, or any other non-finite result (e.g. SQRT of a negative number)
#NAME?Unknown function name

A function that produces #ERR invalidates the whole formula, even when nested inside another function — =SUM(SQRT(-4), 5) is #ERR, not 5.


Formulas in Context

Hover over any result cell to see the original formula. Formulas are stored in the markdown — the plugin only changes how they're displayed.

When you click into a formula cell in Live Preview, the raw formula reappears for editing. Click away and the result renders again.


Example: Budget Tracker

{{calc}}
| Category     | Budget      | Spent       | Remaining   |
|--------------|-------------|-------------|-------------|
| LLC setup    | 500         | 200         | =B1-C1      |
| Dev tools    | 200         | 99          | =B2-C2      |
| Marketing    | 300         | 0           | =B3-C3      |
| **Total**    | =SUM(B1:B3) | =SUM(C1:C3) | =SUM(D1:D3) |

Example: Sales Table

{{calc}}
| Product | Price | Units | Revenue     | Tax (10%)   |
|---------|-------|-------|-------------|-------------|
| Widget  | 29    | 12    | =B1*C1      | =D1*0.1     |
| Gadget  | 49    | 7     | =B2*C2      | =D2*0.1     |
| Totals  |       |       | =SUM(D1:D2) | =SUM(E1:E2) |

Installation

From Obsidian Community Plugins

  1. Open Settings → Community Plugins
  2. Click Browse and search for Table Calc
  3. Click Install, then Enable

Manual Installation

  1. Download main.js, manifest.json, and styles.css from the latest release
  2. Create a folder: <your vault>/.obsidian/plugins/table-calc/
  3. Copy the three files into that folder
  4. In Obsidian: Settings → Community Plugins → reload → enable Table Calc

Commands

CommandDescription
Evaluate table formulas in this noteRe-runs formula evaluation on all {{calc}} tables in the active note. Useful if a table doesn't update automatically.

Access via Cmd+P (Mac) or Ctrl+P (Windows/Linux).


How It Works

Formulas are stored as plain text in your markdown file — the plugin never modifies the source. A MutationObserver watches for rendered tables and evaluates any =formula cells on the fly. Only tables immediately preceded by a {{calc}} paragraph are processed; all others are ignored. In Reading view the cell's display is replaced with the computed result; in Live Preview the raw formula stays visible (tinted, since those cells are natively click-to-edit and rewriting their text would break Obsidian's cursor placement) and the result shows as a tooltip on hover instead.

This means your notes remain portable: open them anywhere and you'll see the raw formulas. Enable the plugin and you see the results.


Testing

npm test runs the automated suite: engine.test.js covers the formula engine directly, and main.test.js exercises processTable's DOM handling (via jsdom) — in particular, that Live Preview never rewrites a formula cell's text (Obsidian's Live Preview tables are natively click-to-edit, and CM6 maps cursor position by walking the cell's rendered text, so any change to it desyncs that mapping and corrupts editing).

test/example-vault-note.md is a manual fixture, not run by npm test. Copy it into any vault with this plugin installed to eyeball formula evaluation, error handling (#ERR/#NAME?), and Live Preview vs. Reading View rendering side by side — every Result cell should match the Expected cell next to it (Section 6 is deliberately the exception).


Limitations

  • Column letters support A–Z (26 columns max)
  • Circular references are stopped at depth 20 and return 0
  • Formulas only evaluate in Live Preview and Reading view, not in Source mode
  • Function arguments must be cell references, ranges, or literal numbers — not inline expressions (use =ABS(A1), not =ABS(A1-B1))
  • A cell counts as numeric only if it's a complete, well-formed number. 1,234 (thousands separator), 5 apples (trailing text), and the literal text Infinity/NaN are all treated as text, not as the number they might resemble — they're excluded from COUNT. This is intentional: parseFloat in JavaScript would otherwise silently read 1,234 as 1 and the string "Infinity" as the number Infinity.
  • Non-numeric cells are handled differently depending on the function: SUM/AVERAGE treat them as contributing 0 (so a stray text cell skews a total or average rather than being skipped). MIN, MAX, MEDIAN, PRODUCT, STDEV, and VAR instead exclude non-numeric cells entirely, since a phantom 0 would distort those results far more severely (e.g. zeroing out an entire PRODUCT, or pulling a MEDIAN/STDEV toward a value no cell actually contains).
  • Numbers are standard JavaScript doubles (IEEE 754), the same numeric type spreadsheets like Excel use. Integers beyond 2^53 (~9 quadrillion) lose precision, and results are snapped to 8 decimal places to absorb ordinary binary floating-point drift (e.g. 0.1+0.2 reliably shows 0.3, not 0.30000000000000004)
  • ROUND rounds half away from zero (ROUND(2.5,0)3, ROUND(-2.5,0)-3), matching spreadsheet conventions rather than JavaScript's native Math.round (which rounds -2.5 to -2)
  • References are positional, not tracked. A2 always means "column A, row 2 of the table as it exists right now" — there's no concept of a formula "belonging" to a row. If you insert, delete, or reorder rows, formula text doesn't shift to compensate, so a formula can silently start pointing at the wrong cells. Re-check (or rewrite) formulas after restructuring a table. This is intentional: the plugin never modifies your markdown source, and auto-shifting references would require doing exactly that

Disclaimer

Table Calc is designed for personal notes, budgets, and quick calculations — the kind of arithmetic you'd otherwise reach for a spreadsheet for. It is not intended for safety-critical, financial-regulatory, or any other high-stakes computation. Results are rendered in-browser using JavaScript's standard IEEE 754 floating-point arithmetic and are subject to the same rounding characteristics as any spreadsheet. Always verify critical numbers independently.


License

MIT

For plugin developers

Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.