onFocus so your app can run custom logic — navigation, uploads, etc.
Decorator model
A decorator renders only when it has a non-empty
icon or label. Action-only entries are stored but not displayed.
Constructing a path
Every path starts withpageId/fieldPositionId. What you append after that determines what gets decorated.
Reserved keywords. The path grammar uses three reserved tokens —schemas,rows, andcolumns. Anything else in a path slot is treated as an id (page id, field-position id, row id, column id, or schema key). Don’t use these keywords as ids.
Field decorators
Just the two ids. Applies to the field’s header.Table — /rows, /columns/colId, or specific rowId / rowId/colId
A table has four decorator scopes, two common (defaults applied everywhere) and two specific (overrides for one row or cell):
Specific paths inherit from the matching common path on the first write — anything you set on
/rows shows on row_42 until you write to row_42 directly.
Collection — same as table, plus /schemas/schemaKey/… for nested rows
A collection’s root rows behave like a table — the four scopes above use the exact same path shapes.
Take a “People” collection where each person row holds a nested “Addresses” schema:
schemas/schemaKey/…, no parent walk needed:
A specific nested row or cell lives under a particular parent. Walk through that parent’s row id, then
schemas/sk/, then the nested row id:
If
addresses itself had children, you’d chain another schemas/.../rowId/… after addr_home — the same pattern repeats for every level.
Schema keys come from the field’sschemamap. The schema markedroot: trueholds top-level rows; itschildrenarray names the nested schemas reachable from a row in this schema.
API
Four methods, all onDocumentEditor. Errors are reported via onError.
Behavior to know
- Copy-on-write seed. First write to a row-self / cell scope seeds from the matching common scope, so existing common decorators stay visible on that row alongside your override. Subsequent writes diverge freely.
-
Collection license gating. Writes against a collection field require a license that enables collection features. Without it, the call emits
decoratorErrorand is rejected.
Handling taps
Decorator taps come throughonFocus with the decorator’s action exposed on the field event’s type / target. rowIds / columnId / parentPath on FieldIdentifier tell you where the user tapped.
Errors
All four APIs report throughonError as JoyfillError.decoratorError(DecoratorError):
- Path didn’t resolve (bad ids, deleted row, malformed grammar)
- Validation (
actionempty,colornot#RRGGBB) - Duplicate
actionin batch or against an existing entry removeDecorator/updateDecoratorwith an unknownaction- Collection write without a valid license
getDecorators) on an unresolvable path also emit onError and return [].
Display limits
DecoratorConfig, passed to DocumentEditor at init, controls how many decorators render inline before the rest collapse into a kebab menu.
Supported icons
The SDK maps common names to bundled artwork or SF Symbols, including:camera, import, paperclip, image, file, comment, comments, upload, download, rotate, cloud, filter, share, paper-plane, folder, folder-open, magnet, eye, circle-info, add, plus, print, flag, pencil, pen-to-square. Unknown names fall back to a default symbol.