Signatures
Anchored cell signatures via drawn / typed / uploaded surfaces. Same pipeline as Casual Editor; sheet-flavored anchors.
Casual Sheets ships the same document-signature pipeline as Casual Editor. Drive integrators who built a signing flow against the editor port to sheets by swapping field anchors from { kind: 'doc', paraId } to { kind: 'sheet', sheet, cell }. Everything else — banner, mode, complete event, cancel — is identical.
What the editor handles
- Renders the floating signing pane (right-anchored sidebar).
- Walks the signer through configured fields (
sequential/concurrent). - Three capture surfaces — draw (PNG), type (UTF-8 in a script font), upload (image file).
- Emits per-field progress events; one completion event when every required field is done.
- Honours cancellation.
What the host owns
- Signer identity and the auth token.
- Signature material — drawn PNG, typed string, uploaded PNG/JPEG/SVG, or X.509 detached signature from your CA.
- Audit trail — your backend persists the per-field events.
- Final stamping into the
.xlsx— for v1, the editor returns the unstamped workbook + afieldsmap; your backend (Rust +umya-spreadsheet/ OpenXML in any language) does the final composition.
This split keeps the editor cert-free and lets you plug in any signing backend.
Anchor — the sheet-specific bit
A signature field anchors to a cell in a named sheet:
{
fieldId: 'accountant',
label: 'Accountant signature',
required: true,
anchor: { kind: 'sheet', sheet: 'Q3 P&L', cell: 'B47' },
methods: ['drawn', 'typed'],
}
How signatures render:
- Drawn signatures stamp as floating images over the cell range.
- Typed signatures land in the cell directly.
- Uploaded signatures stamp as floating images (the user’s chosen PNG/JPEG/SVG).
Everything else about the flow — banner, sequential mode, complete event, cancel — is identical to the editor flow.
SDK integration
import { SigningProvider, SigningPane } from '@/signing';
<SigningProvider session={signingSession} documentBytes={currentBytes}>
<YourSheetMount />
<SigningPane banner="Signing as Alice for Acme Co." />
</SigningProvider>;
Where signingSession is a SigningSessionConfig:
{
mode: 'sequential',
fields: [
{
fieldId: 'employee',
label: 'Employee',
required: true,
anchor: { kind: 'sheet', sheet: 'Payroll', cell: 'C12' },
methods: ['drawn', 'typed'],
},
{
fieldId: 'manager',
label: 'Manager',
required: true,
anchor: { kind: 'sheet', sheet: 'Payroll', cell: 'C13' },
methods: ['drawn'],
},
],
banner: 'Signing as Alice for Acme Co.',
onFieldSigned: async ({ fieldId, method, bytes, mime, signedAt }) => {
await myBackend.audit.signatureField({ fieldId, method, signedAt });
},
onComplete: async ({ bytes, fields }) => {
const stamped = await myBackend.stampSignatures(bytes, fields);
await myFileSource.save(workbookId, stamped);
onSigningDone();
},
onCancel: ({ reason }) => onSigningAborted(reason),
}
Iframe integration
The same envelope shapes flow over postMessage — see iframe embedding. The host sends casual.signature.request, listens for casual.signature.field.signed per field and casual.signature.complete at the end.
Sequence — three-signer concurrent flow
Host Editor (sheet)
──── ──────────────
casual.signature.request(fields × 3, render signing pane, all three
mode='concurrent', banner) ───► fields highlighted; signer picks
order
…signer A clicks accountant cell B47 → draws…
◄────── signature.field.signed(accountant)
…signer B clicks reviewer cell B48 → types…
◄────── signature.field.signed(reviewer)
…signer C clicks witness cell B49 → uploads PNG…
◄────── signature.field.signed(witness)
◄────── signature.complete(bytes, fields)
host stamps signatures into .xlsx,
writes audit rows, archives
What’s deferred
- Editor-side cell stamping — v1 returns the unmodified workbook; your backend composes the final
.xlsx. v2 lands client-side stamping (image insertion at cell range) so single-page hosts can finalize client-side. - Univer-canvas decorations — currently the signing pane overlays Univer’s canvas; it doesn’t paint signature affordances directly onto cells. A future pass could add data-validation-style indicators on anchored cells.
Editor parity
See the Casual Editor signatures guide for the same flow with paragraph anchors. The two docs cover the same protocol from different sides.