Canvas Items And CanvasBuilder
What It Is
This chapter explains the practical authoring model behind Jetstack canvases:
- how CanvasBuilder works
- what a canvas item is
- how item settings are stored
- how nested items, active areas, scopes, and runtime values work
- which item families are available and when to use them
Use this chapter after reading:
Why It Matters
Most of the real power of canvases does not live in the top-level canvas form. It lives in the item tree edited in CanvasBuilder.
If you understand CanvasBuilder well, you can:
- assemble full pages
- embed views, forms, and nested canvases
- work with object context
- prepare variables for later items
- build reusable fragments
- create property-oriented templates
Mental Model
A canvas is a tree of items.
Each item has:
- a stable generated item ID
- a title used in the builder
- a class defining what the item does
- input parameters whose values are expressions evaluated at render time
- optional child zones called active areas
- optional hidden state
- optional elevated-permissions state
At runtime, the canvas renderer walks the tree and asks each item to produce HTML. Each item's expressions are evaluated against the canvas's code processor, with the surrounding tree context (object wrapper, iterator, current user, …) bound in as variables.
The result is not a flat HTML template authored by hand. It is a structured composition graph stored as serialized item objects.
A Note On Legacy Canvases
Some canvases authored before the current expression model may still hold their input parameter values in the legacy chain-builder format. They keep working without changes. When you open the settings modal of such an item, the builder shows a one-click migration assistant that translates the stored chains into the current expression form, flags any parts that need a manual rewrite, and lets you confirm the conversion before committing it. After migration the item behaves like any newly created one.
How CanvasBuilder Works
CanvasBuilder is the dedicated authoring interface for the item tree.
Its main working areas are:
- the item gallery on the left
- the editable canvas area on the right
- the draft indicator and publish controls
- the meta dialog
- the item settings modal
- the parameter-arguments modal
Draft Workflow
CanvasBuilder loads the draft if one exists. Otherwise it loads the published content.
This means:
- edits normally go into
content_draft - the live canvas keeps using
contentuntil you publish
The builder exposes:
PublishDiscard draft
Use this workflow when:
- the canvas is already live
- you want to iterate safely
Core Builder Operations
Add Item
How it works:
- drag or drop from the item gallery into the main canvas or into an item's active area
What it means:
- the builder creates a new item instance of the chosen class
- if added into a child zone, the item becomes part of that parent item's active area
Move Item
How it works:
- drag an existing item to a new position or zone
What it means:
- the builder reorders the serialized tree or moves the item to a different active area
Copy Item
How it works:
- use the item's copy action
What it means:
- the item is cloned
- the copy receives a new item ID
- child items also receive regenerated IDs
Use it when:
- a block should be duplicated and then adjusted
Delete Item
How it works:
- use the delete action on the item
What it means:
- the item is removed from the canvas tree
- child items inside it are removed with it
Rename Item
How it works:
- change the item title in the builder
What it means:
- the title improves builder readability
- it usually does not change runtime behavior directly
Use titles generously for:
- repeated similar items
- layout sections
- nested forms
- reusable snippets
Set a Public ID
How it works:
- click the link-icon button next to Change title in the item's edit controls
- enter a free-form identifier (e.g.
my-card,profile-row) - the current value is shown as a small badge; click the badge to copy it
What it means:
- the rendered wrapper element gets
data-soopio-id="<your-id>" - Run JavaScript automation code can target it via
Jetstack.getElement('<your-id>')orJetstack.getElements('<your-id>') - the Public ID survives duplication and is independent of the internal item ID and any HTML
idinput parameter - when the item is rendered inside an iterator, each row gets
<your-id>#<iteratorUniqueId>— useJetstack.getElementsto match every row
Use Public IDs for any canvas item you plan to reference from a RunJavaScriptAction.
Hide Item
How it works:
- toggle the hidden flag in the builder
What it means:
- hidden items do not render in runtime mode
- they can still remain in the builder tree for later use or temporary suppression
Use it when:
- testing alternatives
- parking a block temporarily
- disabling one section without deleting its configuration
Elevated Permissions
How it works:
- toggle the item's elevated-permissions flag
What it means:
- the item can request a more privileged execution mode in the places that honor this flag
- this is especially relevant for some form and operation items
Use it carefully:
- elevated permissions are a governance decision, not only a convenience setting
Item Anatomy
Every item class defines its own configuration through input parameter definitions.
Those definitions can specify:
- parameter name
- expected type
- default value
- UI control type
- conditional visibility
- redraw-on-change behavior
- value picker type
- context for resource pickers
- whether the value should be sandboxed before rendering
Shared Item Parameters
Most items inherit several common parameters.
class
What it controls:
- HTML class added to the wrapper output
Use it when:
- a block needs styling hooks
- a custom wrapper class improves CSS targeting
id
What it controls:
- HTML ID added to the rendered wrapper
Use it when:
- a block needs a DOM anchor or JS hook
reloadDuringAjax
What it controls:
- whether the item should be redrawn during AJAX updates
Use it when:
- the item output depends on state that changes during AJAX operations
isReloadableContent
What it controls:
- whether the item should expose itself as reloadable content
Use it when:
- the item is a content region that should be refreshable after interactions
iterate
What it controls:
- whether the item should repeat over an iterable source
Why it matters:
- this is one of the key ways canvases become data-driven
- iterated items gain iterator context for nested content
Active Areas
An active area is a named child zone inside an item.
Examples:
- a
Rowhas an inner area for columns - an
Ifitem hasif_trueandif_false - a
Cardhas areas for body-like child content - a
CustomFormhas aninnerarea for fields
Why it matters:
- active areas are what make nesting possible
- they let layout and structural items act as containers rather than only leaf nodes
Use them to:
- create layout structure
- separate conditional branches
- embed fields inside forms
- build nested fragment hierarchies
Values In Item Settings
Each input parameter on a canvas item holds an expression. The expression is evaluated by the canvas's code processor when the item is about to render, against the surrounding tree context.
In practice, an expression can be:
- a literal:
42,'hello',true,false,null - a reference to an in-scope variable:
currentUser,iteratorItem.email,parentObject.id - a function call:
today(),concat('Hello, ', currentUser.first_name),appParameter('id') - a chained property access through relations:
iteratorItem.created_by.email - arithmetic, boolean, and ternary expressions:
iteratorItem.price * 1.21,currentUser.email ?? 'guest' - rich-text content with embedded shortcodes (in editor-mode fields, see below)
The settings modal renders one editor per parameter. Most parameters use a code editor with autocomplete; the rest use specialized controls (selects, checkboxes, type pickers, rich-text editors) when the parameter type calls for one.
Resource Pickers
Some parameters declare a valueType, which means the builder treats them as references to platform resources and renders a dedicated picker instead of a free-form expression editor.
Common picker types include:
- automation
- canvas
- email template
- module
- property
- query
- role
- type
- view
Some also declare a valueTypeContext, which means the valid options depend on another parameter. For example, a property picker uses typeId as its context so the builder offers the properties of the chosen type.
Rich-Text Editor Mode
A few content items (notably P) offer a switch between an Editor mode (TinyMCE rich-text) and an Expression mode (code editor). Use Editor mode when the value is mostly static markup with a few dynamic insertions; use Expression mode when the value is a single computed expression.
In Editor mode, dynamic insertions use the shortcode forms documented under Shortcodes In Rich-Text Fields.
Conditional Parameters
Item parameters can appear or disappear depending on other parameter values.
Examples:
- the canvas item's advanced selector is shown only when the main canvas selector is set to
_advanced_ - the embedded view item shows different fields depending on whether it is using a defined view, a query, parameter-built query, or custom SQL
Why it matters:
- the settings UI is adaptive
- think of an item as a small stateful configuration object, not a flat form
Redraw-On-Change Parameters
Some parameters cause the settings table to redraw when they change. Selecting one mode (e.g. switching inputType between Editor and Expression on a P item) can reveal entirely different follow-up fields, and changing a base parameter can change the available downstream choices.
Available Context
When you author an expression for an item, the canvas exposes a set of in-scope variables and helper functions. What is in scope depends on where the item sits in the tree.
Always Available
These variables and helpers exist in every item, regardless of position:
| Token | Meaning |
|---|---|
currentUser | The currently authenticated user resource |
true, false, null | Literal values |
var('name') | A canvas-level variable set by Set variable items or by preload automation |
templateVar('name') | A variable from the surrounding page template |
env('name') | A tenant-wide environment variable from app settings |
appParameter('name') | A request/route parameter |
selection() | The selection app parameter (id + selection list combined) |
formStatus('formId') | Submission status of a form by its form id |
queryResultCount(queryId) | Number of rows for a stored Query |
queryResultCalc(queryId, 'propId', 'code') | Calculation result for a stored Query |
today(), date(...), formatDate(...) | Date helpers |
concat(...), map(...), length(...) | String and collection helpers |
+, -, *, /, ==, !=, &&, ` |
The full helper catalog is shared with automations: see Code Processor Functions.
Tree-Position-Derived
Two variables depend on what kind of ancestor wraps the item:
| Token | When it resolves |
|---|---|
iteratorItem | The current item of the nearest iterator-role ancestor (GeneralIterator, QueryIterator, TableGeneralIterator, or any item with iterate set) |
iteratorIndex | The zero-based index in that iteration |
parentObject | The pinned object of the nearest non-iterator Object wrapper ancestor — iterators are transparently skipped, so parentObject always refers to the surrounding "real" object context |
The truth table for typical nestings:
| Ancestor chain (innermost → outermost) | iteratorItem | parentObject |
|---|---|---|
| (none) | — | — |
Object wrapper(Order) | — | Order |
GeneralIterator(Product) | current Product | — |
Object wrapper(Order) → GeneralIterator(LineItem) | current LineItem | Order |
Object wrapper(Order) → Object wrapper(Customer) | — | Customer (innermost wrapper wins) |
Object wrapper(Order) → GeneralIterator → GeneralIterator | innermost iterator's item | Order |
The rule: iteratorItem follows the nearest iterator-role ancestor; parentObject follows the nearest non-iterator object wrapper.
Type-Aware Autocomplete
When you place the cursor in an expression editor, the canvas builder offers two complementary aids.
Variables Panel
A collapsible panel above the parameter table shows every variable currently in scope, grouped by source (Built-in, Functions, Iterator, Parent object, Canvas variables). Click a chip to insert it at the caret of the most recently focused expression editor.
When iteratorItem or parentObject resolves to a known typed object (the surrounding ancestor declares a fixed typeId), the panel expands to list that type's fields directly, e.g. iteratorItem.email, iteratorItem.created_on, parentObject.title.
Inline Hints
Inside the editor, two hint sources are blended:
- typing a known root and a dot —
iteratorItem.,parentObject.,currentUser.— opens an inline list of that type's fields. Continuing through a relation extends the chain:iteratorItem.created_by.follows the user relation and offers User's fields. - typing any identifier —
con,cur,for, … — offers the matching builder-in functions and root variables.
Ctrl+Space triggers the same hint provider manually. Hints are resolved live: when you cross from a known type into a relation that hasn't been seen before, the builder asks the server for that type's schema and serves the hints on the next keystroke.
When the surrounding ancestor's typeId is itself dynamic (set by another expression), the hint system falls back to the bare root — you can still type the chain, you just don't get autocomplete past the root.
See also:
Applying Changes
The settings modal accumulates expression edits locally. Nothing is persisted to the canvas draft until you click Apply changes, at which point the entire set of changed expressions for that item is committed in one round trip and the canvas redraws. Closing the modal without applying discards the pending edits.
This is intentional: it lets you experiment freely inside the modal without polluting the draft until you are satisfied with the whole configuration.
Pickers (selects, checkboxes, resource pickers) commit immediately on change because they often need to drive redrawOnChange behavior in the same modal.
Shortcodes In Rich-Text Fields
Rich-text Editor-mode fields support two embedded shortcode forms inside the HTML content. They are evaluated against the same code processor and tree context as expression-mode fields.
| Form | Resolved by | Use it for |
|---|---|---|
{=expression} | The canvas code processor | Inline computed values, function calls, conditionals: {=currentUser.first_name}, {=concat('#', parentObject.id)} |
{$variable.path} | Variable resolution against the canvas context | Plain context lookups in legacy or simpler form: {$currentUser.email} |
Errors during shortcode evaluation are swallowed — a malformed {=...} fragment renders as the original placeholder rather than breaking the page.
See:
Item Families
The item gallery is grouped by capability. The exact classes come from the canvas item registry, but in practice the gallery is organized around these families.
Layout Items
These items define structure and placement.
Common layout items:
IfBlockRowColSpacerCardTabs
Use them when:
- you need layout hierarchy
- content should be conditionally shown
- sections should be visually grouped
- the canvas needs a clear page structure
Special note on If:
- it has
if_trueandif_falsechild areas - it is a structural branching tool inside the canvas itself
Content Items
These items render content-oriented structures.
Common content items:
TableTable customTrTdTableGeneralIteratorTableQueryIteratorH1toH6PSpanImageLink
Use them when:
- the canvas needs textual or media content
- you want manual tabular structure
- repeated content should be rendered row by row
Object Items
These items work with object context and object rendering.
Common object items:
Object wrapperObject renderProperty valueObject overviewObject commentsGeneralIteratorQueryIterator
Why they matter:
- they are the main bridge between the canvas and Jetstack's data model
Object wrapper
Use it when:
- a subtree should work against one current object context
- child items need
parentObjectaccess
Object render
Use it when:
- you want the platform to render a whole object surface inside the canvas
Property value
Use it when:
- a canvas should display one specific field from an object
Iterators
Use them when:
- one block should repeat over a general iterable or query result
- child items should gain iterator context
Widget Items
These items are general-purpose compositional helpers and integrations.
Common widget items:
Set variableSet variable by AutomationSet variable by CallbackViewCanvasCustom HTMLReplicator item template
Variable Items
Use them when:
- later items need a prepared canvas variable
- a preload automation would be too broad for one local value
Embedded View
Use it when:
- a canvas should embed a normal Jetstack view
Its main modes are:
- defined view
- dynamic view with defined query
- dynamic view from query parameters
- dynamic view from custom SQL
This makes it one of the most important bridge items between canvases and views.
Embedded Canvas
Use it when:
- one canvas should render another canvas
This is the main composition mechanism behind snippet-like reuse.
Custom HTML
Use it when:
- the layout needs custom markup that is still anchored inside the canvas item model
Important behavior:
- it supports a gallery of nested child elements exposed through shortcodes
- it also supports injected variables
Use it carefully:
- prefer structured items where possible
- reach for custom HTML when the structured item palette is not expressive enough
Replicator item template
Use it when:
- building property-oriented repeated-entry layouts, especially for replicators
Form Items
These items build custom forms and form fields inside canvases.
Common form items:
Custom formFormCustomFormFieldFormFieldFormLabelFormControl
Why they matter:
- forms are one of the strongest reasons to use canvases
- they let you build custom entry and editing flows with automation hooks
Custom form
Use it when:
- the canvas should host a fully custom form layout and field set
Form
Use it when:
- the canvas should host a structured object form tied to a type and form mode
Form Event Automations
Form items can wire automations to events such as:
- anchor
- reload
- validate
- submit
- success
- after success
- error
This makes forms inside canvases highly composable with the automation system.
Choosing The Right Item Family
Use this rule of thumb:
- choose Layout items to shape space
- choose Content items to render text, media, or manual structure
- choose Object items to bind the canvas to domain data
- choose Widget items to compose behavior and embed other platform surfaces
- choose Form items when the canvas becomes an input flow
Common CanvasBuilder Patterns
Page Canvas With Object Context
Typical structure:
Object wrapper- layout items for sections
- property-value or object-overview items
- embedded view blocks for related records
Use it for:
- detail pages
- rich object dashboards
Reusable Snippet Canvas
Typical structure:
- a small layout skeleton
- a few object-aware or variable-aware items
- optional custom HTML for tight presentation
Use it for:
- shared summary blocks
- headers
- reusable side sections
Widget Canvas
Typical structure:
- small layout
- one or two variable-setting items
- one embedded view or KPI-oriented fragment
Use it for:
- dashboards
- role-specific summary panels
Custom Form Flow
Typical structure:
Custom formorForm- field items
- automation hooks on anchor, validate, submit, and success
Use it for:
- guided entry flows
- custom object editing experiences
- property-level repeated-entry templates
Practical Guidance For Safe Builder Work
- Use titles on items so the tree stays understandable.
- Keep one clear responsibility per item whenever possible.
- Prefer structured items before custom HTML or callback code.
- Use snippet canvases to avoid duplicating large blocks.
- Keep variable-setting items close to the sections that use them.
- Use iterators deliberately and make sure nested content clearly depends on them.
- Treat elevated permissions as an exception, not a default.
- Publish intentionally and use drafts for experimentation.
Design Questions To Ask While Building
- Does this canvas really need a custom block here, or would a standard embedded view be better?
- Should this value be a literal, derived from
parentObject/iteratorItem, or a computed expression? - Does this subtree need object context (an
Object wrapper) or iterator context (aGeneralIterator/QueryIterator)? - Would a reusable snippet be better than repeating the same block in several canvases?
- Is custom HTML solving a real limitation, or hiding an avoidable design problem?