KQ-1735 · CELL/NOTES

Cell Notes

A spreadsheet whose notes live in their cells: every annotated cell carries a small corner, and opening a note grows its card out of that corner — one value on springs.glide sweeps a diagonal crease across the card's clip with a lip of paper along it, so the note unfolds from the cell — while closing folds it back on the exit ease. Replies stack inside the card on springs.snap, resolving folds the corner back flat on snap, and the active cell's outline travels cell to cell on snap. It is a real role="grid" with one roving cell: arrows, Home, End and Ctrl+Home/End move, Shift+F2 opens or starts the active cell's note, Escape closes it and returns focus, and the notes sidebar becomes a sheet below a 40rem container.

KQ-1735 · CELL/NOTES

Fernworks · FY27 budget

4 notes · 3 open

B2$412,000

Arrow keys move between cells. Shift with F2 opens the cell's note or starts one, Enter opens a note, Escape closes it.

Row
A
B
C
D
E
F
1
Line item
Q1
Q2
Q3
Q4
Total
2
Payroll
$412,000
$418,000
$431,000
$436,000
$1,697,000
3
Contractors
$64,000
$58,000
$72,000
$49,000
$243,000
4
Cloud hosting
$38,500
$41,200
$44,900
$47,300
$171,900
5
Field equipment
$22,000
$6,500
$31,000
$8,200
$67,700
6
Travel
$18,400
$21,900
$16,300
$24,800
$81,400
7
Training
$9,000
$9,000
$12,500
$7,000
$37,500
8
Office
$26,000
$26,000
$26,000
$26,000
$104,000
9
Total
$589,900
$580,600
$633,700
$598,300
$2,402,500

B2 · no note · 3 open

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/cell-notes

Props

cells
CellNotesValue[][]
default defaultCellNotesCells
The sheet, row by row (strings, numbers or null); row 1 is the sheet's own heading row.
columns
CellNotesColumn[]
default defaultCellNotesColumns
Per column, A first: { width?, kind?: "text" | "money" | "number" | "percent" }.
strongRows
number[]
default [1, 9]
Row numbers (from 1) drawn bold, like headings and totals.
notes / defaultNotes
CellNote[]
default — / defaultCellNotes
Notes as { id, cell: "C4", author, at, text, replies: { id, author, at, text }[], resolved? }, controlled or initial.
onNotesChange
(notes) => void
default —
Fires with every note after an add, a reply or a resolve.
active / defaultActive / onActiveChange
string
default — / "B2"
The active cell as a reference, controlled or initial, and the callback from the click or key that moved it.
open / defaultOpen / onOpenChange
string | null
default — / null
The open note's id, controlled or initial, and the callback when a card opens or closes.
onAdd
(note) => void
default —
A note was added to a cell; it is already in the list.
onReply
(noteId, reply) => void
default —
A reply was posted on a note.
onResolve
(noteId, resolved) => void
default —
A note was resolved (true) or reopened (false).
cornerStyle
"fold" | "flag" | "dot"
default "fold"
A folded paper corner whose card unfolds with a lip of paper, a flat flag, or a dot (the card grows by clip alone).
density
"compact" | "regular" | "roomy"
default "regular"
Row height (28/32/38px), cell type and card width.
accent
string
default "var(--accent-bright)"
Corners, the active outline, the card's top edge and Reply — any CSS colour, taken at a fixed lightness.
locale
string
default "en-US"
Locale for numbers and money.
currency
string
default "USD"
Currency for money columns.
author
string
default "Noor Haddad"
The name new notes and replies are posted under.
now
number | Date
default defaultCellNotesNow
The moment relative times count from, so server and browser render the same text.
title
string
default "Fernworks · FY27 budget"
The sheet's name and the surface's accessible name.
status
"ready" | "loading" | "error"
default "ready"
Loading shows a skeleton sheet and notes; error shows Try again.
onRetry
() => void
default —
Try again was pressed after the sheet failed to load.
height
number
default 540
The surface's height in px; the grid and the notes scroll inside it.
disabled
boolean
default false
Read only: notes open and read; nothing is added, replied to or resolved.
className
string
default —
Classes for the surface.