Directives
Directives use :::name ... ::: syntax to mark semantic regions of your template (similar to fenced code blocks in Markdown). Each directive compiles to the appropriate structure for each channel.
Norq has 16 directives: 12 content directives, 3 control flow directives, and :::table for iterable data tables.
Directive parameters
Content directives accept optional parameters after the name. These affect email rendering (other channels ignore them). Parameters are space-separated — order doesn't matter. Expressions like {{var}} are supported.
| Parameter | Syntax | Effect |
|---|---|---|
| Alignment | center, left, right |
Text alignment |
| Spacing | compact, spacious |
Reduced or increased padding |
| Background | bg=#hex |
Background color override |
| Text color | color=#hex |
Text color override |
| Image URL | bare URL or {{var}} |
Background image (hero only) |
All content directives (header, footer, callout, highlight, fields, centered, hero) support all parameters. Expressions like {{variable}} are resolved in params.
Examples:
::: header center bg=#1e3a5f color=#ffffff
White text on dark header
:::
::: callout bg=#fff3cd color=#856d0e
Warning-styled callout
:::
::: footer right color=#999999
[Unsubscribe]({{unsubscribe_url}})
:::
::: hero {{hero_image_url}}
# Dynamic background image
:::Content directives
:::header
Top section of the notification -- logos, brand name, title.
::: header
Order Shipped
:::| Channel | Compilation target |
|---|---|
| Background-colored MJML section with text | |
| SMS | Ignored |
| Slack | Block Kit header block (plain_text) |
| Push | Title source (highest priority) |
Bold text (*header text*) |
|
| Teams | TextBlock with ExtraLarge + Bolder |
:::footer
Bottom section -- legal text, unsubscribe links, context.
::: footer
[Unsubscribe]({{unsubscribe_url}})
:::| Channel | Compilation target |
|---|---|
| Small-font MJML section (12px, #666) | |
| SMS | Appended after newline |
| Slack | Context block (mrkdwn) |
| Push | Ignored |
| Footer text in interactive messages; ignored in text-only | |
| Teams | TextBlock with isSubtle=true, size=Small |
:::table
Iterable data table — combines table rendering with array iteration. Header row renders once, template row repeats per item. Supports variable pipe arguments in cells.
::: table products as item
| Product | Qty | Subtotal |
|---------|-----|----------|
| {{item.name}} | {{item.qty}} | {{item.cost | multiply item.qty | currency "USD"}} |
:::| Channel | Compilation target |
|---|---|
HTML <table> with styled header and data rows |
|
| SMS | Pipe-separated text (Product | Qty | Subtotal) |
| Slack | Bold headers + pipe-separated rows in a section |
| Push | Pipe-separated text |
| Pipe-separated text | |
| Teams | Adaptive Card FactSet |
If the collection is empty, only the header row renders (empty table). The | inside {{ }} expressions is handled correctly — it won't break column separation.
:::action
CTA buttons. Contains Markdown links with style hints.
::: action
[Track Order]({{tracking_url}}){primary}
[Cancel Order]({{cancel_url}}){danger}
[View Details]({{details_url}}){secondary}
:::Button styles: {primary}, {secondary}, {danger}.
| Channel | Compilation target |
|---|---|
mj-button with href |
|
| SMS | "Label: url" plain text |
| Slack | Actions block with button elements (style=primary) |
| Push | action_url extracted from first link |
| Reply buttons (max 3) in interactive mode; URL buttons in template mode | |
| Teams | Action.OpenUrl entries in card actions array |
:::callout
Highlighted note or warning box.
::: callout
Your payment method will be charged within 24 hours.
:::| Channel | Compilation target |
|---|---|
| Background-colored MJML section (#fff3cd) | |
| SMS | Rendered as plain text (no styling) |
| Slack | Section block with :information_source: prefix |
| Push | Body text with warning symbol prefix |
| Body text with warning symbol prefix | |
| Teams | Container with style=accent |
:::hero
Full-width hero image.
::: hero

:::| Channel | Compilation target |
|---|---|
| Content rendered inline (images become mj-image) | |
| SMS | Ignored |
| Slack | Content rendered as normal blocks |
| Push | Image URL extracted for push image field |
| Image URL extracted; triggers image message type | |
| Teams | Image element with size=Stretch |
:::fields
Key-value pairs, one per line. Useful for order details, invoice line items, etc.
::: fields
Order ID: {{order.id}}
Status: {{order.status}}
Total: {{order.total}}
:::| Channel | Compilation target |
|---|---|
| HTML table with bold keys (font-weight:bold) | |
| SMS | Plain text lines ("Key: Value") |
| Slack | Section block with fields array (mrkdwn: *Key:* Value) |
| Push | Body text lines ("Key: Value") |
Bold key formatting (*Key:* Value) |
|
| Teams | FactSet with title/value facts |
:::media
Embedded image, video, or file. Use the type parameter to specify the media type.
::: media type=image

:::
::: media type=video
[Watch the demo](https://cdn.example.com/demo.mp4)
:::Params: type=image (default), type=video, type=file.
| Channel | Compilation target |
|---|---|
| mj-image for images; link for other types | |
| SMS | URL as plain text; ignored for non-URL content |
| Slack | Image block for images; mrkdwn link for others |
| Push | Rendered as text (graceful degradation) |
| Ignored (hero/images handled separately) | |
| Teams | Image element; altText from alt attribute |
:::columns
Multi-column layout with nested :::col blocks.
::: columns
::: col
**Shipping Address**
123 Main St
New York, NY 10001
:::
::: col
**Billing Address**
456 Oak Ave
San Francisco, CA 94102
:::
:::| Channel | Compilation target |
|---|---|
| MJML native multi-column layout (mj-section > mj-column) | |
| SMS | Stacked sequentially as text |
| Slack | Section block with fields array (one field per column) |
| Push | Stacked as text (graceful degradation) |
| Stacked as text lines | |
| Teams | ColumnSet with Column elements (width=stretch) |
:::list
Styled list.
::: list
- Choose your plan
- Add your team
- Start sending
:::| Channel | Compilation target |
|---|---|
| HTML list inside mj-text | |
| SMS | Numbered lines |
| Slack | Section block with list-formatted mrkdwn |
| Push | Text lines |
| Text lines | |
| Teams | TextBlock with list text |
:::raw
Raw channel-native code. An escape hatch for channel-specific features that directives don't cover.
::: raw
```html
<table style="width:100%">
<tr><td>Custom HTML</td></tr>
</table>
```
:::The content must be a fenced code block inside the directive.
| Channel | Compilation target |
|---|---|
| mj-raw passthrough (HTML inside code block) | |
| SMS | Ignored |
| Slack | Parsed JSON inserted as Block Kit block(s) |
| Push | Ignored |
| Ignored | |
| Teams | Parsed JSON inserted as Adaptive Card element |
:::highlight
Dark card with prominent text. Use for announcements, special offers, or key information that must stand out.
::: highlight
Limited-time offer: 50% off all plans!
:::| Channel | Compilation target |
|---|---|
Dark mj-column (brandColor background, white text, 600 weight, 8px radius) |
|
| SMS | Star prefix (⭐ text) |
| Slack | section block with bold mrkdwn (*text*) |
| Push | Star prefix (⭐ text) |
Bold text (*text*) |
|
| Teams | Container with style=attention and TextBlock |
:::centered
Center-aligned text block. Use for taglines, thank-you messages, or any content that reads better centered.
::: centered
Thank you for being a customer.
:::| Channel | Compilation target |
|---|---|
mj-text with align="center" |
|
| SMS | Plain text (no alignment in SMS) |
| Slack | Plain text (no alignment in Slack) |
| Push | Plain text (no alignment in push) |
| Plain text (no alignment in WhatsApp) | |
| Teams | Plain text (no alignment in Adaptive Cards) |
Control flow directives
:::if / :::else
Conditional rendering. See the control flow page for full details.
::: if order.shipped
Your order has shipped!
:::else
Your order is being processed.
::::::each
Loop over an array. See the control flow page for full details.
::: each order.items as item
- {{item.name}} x {{item.qty}} -- ${{item.price}}
:::