Norq

MS Teams Channel

Norq compiles Teams templates to Adaptive Card v1.5 JSON. Adaptive Cards (Microsoft’s rich message format for Teams) are the standard format for rich messages in Microsoft Teams.

Pipeline: Markdown -> AST (parse tree) -> Adaptive Card JSON

Template files

  • msteams.md – Markdown mode
  • msteams.json – Native JSON mode (for inputs, toggles, custom layouts)

Frontmatter

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

Directive compilation

Directive Teams output
:::header TextBlock with ExtraLarge size + Bolder weight
:::footer TextBlock with isSubtle=true, size=Small
:::action Action.OpenUrl entries in the card actions array
:::callout Container with style=accent
:::hero Image element with size=Stretch
:::fields FactSet with title/value facts
:::media Image element; altText from alt attribute
:::columns ColumnSet with Column elements (width=stretch)
:::highlight Container with style=“attention” containing a TextBlock
:::centered Children rendered as normal card elements
:::list TextBlock with list-formatted text
:::raw Parsed JSON inserted as Adaptive Card element

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 | {{company_name}}
:::

Compiled output

The output is an Adaptive Card JSON structure:

{
  "card": {
    "type": "AdaptiveCard",
    "version": "1.5",
    "body": [
      {
        "type": "TextBlock",
        "text": "Order Shipped",
        "size": "ExtraLarge",
        "weight": "Bolder"
      },
      {
        "type": "TextBlock",
        "text": "Hey Gaurav, your order **#ORD-123** has shipped!",
        "wrap": true
      },
      {
        "type": "FactSet",
        "facts": [
          { "title": "Tracking ID", "value": "TRK-456" },
          { "title": "Delivery", "value": "Mar 30" }
        ]
      },
      {
        "type": "TextBlock",
        "text": "Order notification | Acme Corp",
        "isSubtle": true,
        "size": "Small"
      }
    ],
    "actions": [
      {
        "type": "Action.OpenUrl",
        "title": "Track Order",
        "url": "https://track.example.com/123"
      }
    ]
  }
}

Native JSON mode

For Adaptive Card features beyond what directives cover (Input.Text, Input.Toggle, Action.Submit, ColumnSet with specific widths), use msteams.json:

{
  "$norq": { "enabled": true },
  "type": "AdaptiveCard",
  "version": "1.5",
  "body": [
    {
      "type": "TextBlock",
      "text": "Rate your delivery",
      "size": "Large",
      "weight": "Bolder"
    },
    {
      "type": "Input.ChoiceSet",
      "id": "rating",
      "label": "How was your experience?",
      "choices": [
        { "title": "Excellent", "value": "5" },
        { "title": "Good", "value": "4" },
        { "title": "Average", "value": "3" }
      ]
    }
  ],
  "actions": [
    {
      "type": "Action.Submit",
      "title": "Submit Rating"
    }
  ]
}

Inline formatting

Inline HTML tags in templates are passed through as-is. Adaptive Cards do not render HTML – tags are stripped or ignored by the Teams client. Use Markdown formatting instead.

Adaptive Cards support a subset of Markdown:

Markdown Adaptive Card
**bold** Rendered bold
*italic* Rendered italic
[text](url) Hyperlink
- list item Bullet list
1. list item Numbered list

Partials

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

See Partials for directory layout and authoring details.

Best practices

  • Adaptive Cards have a payload size limit – keep cards focused
  • Use :::fields for structured data (renders as FactSet, which looks great in Teams)
  • Use :::raw with Adaptive Card JSON for interactive elements (inputs, choices)
  • Test with norq preview <name> --channel msteams to validate the card structure
  • Action.OpenUrl is the most compatible action type across Teams clients