Norq

Slack Channel

Norq compiles Slack templates from Markdown to Slack Block Kit JSON (Slack’s native rich message format) with mrkdwn (Slack’s markup syntax, similar to Markdown) formatting.

Pipeline: Markdown -> AST (parse tree) -> Block Kit JSON (blocks + fallback text)

Template files

  • slack.md – Markdown mode (recommended)
  • slack.json – Native JSON mode (for advanced Block Kit features)

Use one or the other, never both.

Frontmatter

---
enabled: true
---
Field Required Description
enabled No true (default) or false. Disables the channel.

Directive compilation

Directive Slack output
:::header header block (plain_text, max 150 chars)
:::footer context block (mrkdwn)
:::action actions block with a single button element (only the first link is extracted; button style is always primary regardless of variant)
:::callout section block with :information_source: prefix
:::hero Content rendered as normal blocks
:::fields section block with fields array (mrkdwn: *Key:* Value)
:::media image block for images; mrkdwn link for others
:::columns section block with fields array (one field per column)
:::list section block with list-formatted mrkdwn
:::highlight section block with bold mrkdwn (*text*)
:::centered Plain text (no alignment in Block Kit)
:::raw Parsed JSON inserted as Block Kit block(s)

Markdown mode example

::: header
Order Shipped
:::
 
Hey {{user.first_name}}, your order *#{{order.id}}* has shipped!
 
::: fields
Tracking ID: {{order.tracking_id}}
Delivery: {{order.delivery_date}}
:::
 
::: action
[Track Order]({{tracking_url}}){primary}
:::
 
::: footer
Order notification
:::

Compiled output

Norq compiles the above template into Block Kit JSON:

{
  "blocks": [
    {
      "type": "header",
      "text": { "type": "plain_text", "text": "Order Shipped" }
    },
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "Hey Gaurav, your order *#ORD-123* has shipped!"
      }
    },
    {
      "type": "section",
      "fields": [
        { "type": "mrkdwn", "text": "*Tracking ID:* TRK-456" },
        { "type": "mrkdwn", "text": "*Delivery:* Mar 30" }
      ]
    },
    {
      "type": "actions",
      "elements": [
        {
          "type": "button",
          "text": { "type": "plain_text", "text": "Track Order" },
          "url": "https://track.example.com/123",
          "style": "primary"
        }
      ]
    },
    {
      "type": "context",
      "elements": [
        { "type": "mrkdwn", "text": "Order notification" }
      ]
    }
  ],
  "text": "Hey Gaurav, your order #ORD-123 has shipped!"
}

The text field is a plain-text fallback for notifications and accessibility.

Highlight

Rendered as a section block with bold mrkdwn text.

::: highlight
New feature: dark mode is here!
:::

Compiles to:

{
  "type": "section",
  "text": {
    "type": "mrkdwn",
    "text": "*New feature: dark mode is here!*"
  }
}

Native JSON mode

For features not covered by directives (date pickers, static selects, overflow menus), use slack.json:

{
  "$norq": { "enabled": true },
  "blocks": [
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "Hey *{{user.first_name}}*, your order has shipped."
      },
      "accessory": {
        "type": "datepicker",
        "initial_date": "{{order.delivery_date}}",
        "placeholder": { "type": "plain_text", "text": "Delivery date" },
        "action_id": "delivery-date"
      }
    }
  ],
  "text": "Order {{order.id}} shipped"
}

Inline formatting

Markdown inline formatting maps to Slack mrkdwn. Inline HTML tags (e.g., <span style="color:red">text</span>) are passed through as-is – Slack strips unrecognized HTML, so they have no visual effect. Use mrkdwn formatting instead.

Markdown Slack mrkdwn
**bold** *bold*
*italic* _italic_
~~strikethrough~~ ~strikethrough~
`code` `code`
[text](url) <url|text>

Testing

tests:
  - name: "Slack has header block"
    channel: slack
    sample: "New user"
    assert:
      blocks: { any: { type: "header" } }
 
  - name: "Slack has action button"
    channel: slack
    sample: "New user"
    assert:
      blocks: { any: { type: "actions" } }

Partials

Partials are reusable template fragments included with {{> partial-name}}. For Slack, partials can also be .blocks.json files containing raw Block Kit JSON. When both header.blocks.json and header.md exist in the partials directory, .blocks.json is preferred for Slack compilation. Block Kit JSON partials support Handlebars control flow ({{#if}}, {{#each}}, etc.).

See Partials for directory layout and authoring details.

Best practices

  • Slack header blocks have a 150-character limit – keep header text short
  • Slack supports max 10 fields per section block – split large field sets
  • Use :::raw with Block Kit JSON for interactive elements (menus, date pickers)
  • The text fallback is auto-generated – do not rely on it for critical content