if- Conditionally render elements based on data or conditionsloop- Repeat elements for each item in an arrayref- Reference elements to check their visibility or propertieschannels- Show elements only on specific channels
Control flow properties are evaluated at render time using Handlebars expressions. You can read
message.data, message.to.data, and other message context.If
Theif property renders an element only when a Handlebars expression is truthy. Otherwise the element is skipped.
When to use:
- Show different content based on user type, subscription status, or feature flags
- Display elements only when certain data exists
- Create personalized experiences based on user context
- Hide elements that aren’t relevant to the current recipient
if field also accepts a structured condition array: one or more condition groups evaluated at render time. The element renders if any group matches, so groups are OR’d together. Within a group, conditions combine using the group’s logical_operator.
Supported property namespaces (dot-paths only):
Supported operators:
Design Studio labels these operators in prose, and three do not match their JSON key. The
editor builds the same object either way. This is the mapping:
The other seven read as their key: equals, is greater than, is less than, contains, does not
contain, is empty, is not empty.
There is no empty structured condition. Delete a group’s last condition and the group goes
with it. Delete the last group and the
if field is removed rather than left as [], so an
empty array is not the way to express “no conditions” and an element carrying one is malformed.
Single group (all conditions AND’d):
value needed):
refs to check element visibility:
String
if and structured if are mutually exclusive on the same element. Use one or the other. String expressions remain fully supported.Ref
Theref property names an element so other elements can reference it. A referenced element exposes its properties plus visible, which says whether it rendered.
When to use:
- Check if another element was rendered before showing related content
- Create dependencies between elements
- Build complex conditional logic based on element visibility
- Access element properties from other elements
elements array.
Basic Example
Loop
Theloop property renders an element multiple times, once for each item in an iterable data source (typically an array).
When to use:
- Display lists of products, orders, notifications, or other array data
- Create dynamic content that adapts to variable-length data
- Build repeating patterns like product cards or notification items
- Iterate over nested data structures
$.item- The current item in the iteration$.index- The zero-based index of the current iteration
$.index for item numbering:
Channels
Thechannels property renders an element only on the channels you list. Use it to show different content on email, SMS, push, and other channels.
When to use:
- Show detailed content in email, concise content in SMS
- Display channel-specific formatting or elements
- Customize content per channel while maintaining a single template
- Hide elements that don’t work well on certain channels
email, push, direct_message, sms, or provider-specific channels like slack, discord, etc.
For a fully different content structure per channel, use .
channels- Element must match current channelif- Condition must evaluate to truthyloop- Element is repeated for each item (if present)ref- Element is registered for reference (if present)
Best practices
- Use
iffor conditional content: Show/hide elements based on data or user context - Use
loopwithgroup: Wrap looped elements in a group for better organization - Reference order matters: Elements must be defined before they’re referenced
- Test with real data: Control flow expressions are evaluated at render time, so test with realistic data structures
- Combine with locales: Use control flow with for fully dynamic, multi-language notifications
- Channel considerations: some elements (like columns) may not render well on all channels