100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
Microsoft 365

Adaptive Cards

Adaptive Cards are a JSON-based UI format for rendering rich, interactive content consistently across bots, tabs, and message extensions in Teams.

Building Teams AppsIntermediate8 min readJul 10, 2026
Analogies

Anatomy of an Adaptive Card

An Adaptive Card is a plain JSON document with a type of AdaptiveCard, a $schema reference, and a version (Teams currently renders up to schema version 1.5, with partial 1.6 support). Its body array holds layout elements — TextBlock for text, Image, Container for grouping, ColumnSet with Column children for horizontal layout, and FactSet for label/value pairs — while a separate actions array holds buttons like Action.OpenUrl, Action.Submit, or the more powerful Action.Execute, which round-trips data to a bot without leaving the card. Because the card is just declarative JSON, the same payload renders consistently whether it's shown inside a bot message, a task module, or a tab, with the host application responsible for the actual rendering.

🏏

Cricket analogy: The body/actions split is like a scorecard display separating the static ball-by-ball log from the interactive buttons for requesting a replay, one section shows information, the other triggers action.

Inputs and Actions

Interactive cards use Input.Text, Input.ChoiceSet, Input.Date, and Input.Toggle elements, each with an id that becomes a key in the data object submitted when the user triggers an Action.Submit or Action.Execute button. Action.Execute (the successor to Action.Submit for bot scenarios) lets the bot return a fresh card to replace the current one, called a refresh, enabling multi-step wizards entirely inside a single card without opening a task module. Action.Submit's data is instead handled client-side or passed to handleTeamsMessagingExtensionSubmitAction in a message extension, while Action.OpenUrl simply navigates the user to an external link and Action.ShowCard reveals a nested card inline for optional secondary input.

🏏

Cricket analogy: Input.ChoiceSet is like a DRS review menu offering a fixed set of choices (umpire's call, out, not out) rather than free text, constraining input to valid options.

Templating and Sending Cards from a Bot

For cards generated dynamically per user or record, the Adaptive Card Templating SDK separates a static template (with ${ticket.title} style bindings) from a data payload, letting a bot render the same layout hundreds of times with different data without string-concatenating JSON. From the Bot Framework SDK, a card is sent as an attachment with contentType application/vnd.microsoft.card.adaptive via CardFactory.adaptiveCard(cardJson), and multiple cards can be sent in a single carousel-style message by adding several attachments with attachmentLayout set to carousel. Designing cards visually (rather than hand-writing JSON) is commonly done in the Adaptive Cards Designer, which also validates against the target Teams schema version before you copy the JSON into your bot code.

🏏

Cricket analogy: Templating with ${ticket.title} bindings is like a broadcaster's lower-third graphic template that auto-fills the current batter's name and score without redesigning the graphic for every player.

json
{
  "type": "AdaptiveCard",
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "version": "1.5",
  "body": [
    { "type": "TextBlock", "text": "${ticket.title}", "weight": "Bolder", "size": "Medium" },
    {
      "type": "FactSet",
      "facts": [
        { "title": "Priority", "value": "${ticket.priority}" },
        { "title": "Assigned to", "value": "${ticket.assignee}" }
      ]
    },
    {
      "type": "Input.ChoiceSet",
      "id": "status",
      "style": "compact",
      "value": "${ticket.status}",
      "choices": [
        { "title": "Open", "value": "open" },
        { "title": "In Progress", "value": "inProgress" },
        { "title": "Closed", "value": "closed" }
      ]
    }
  ],
  "actions": [
    { "type": "Action.Execute", "title": "Update Status", "verb": "updateTicketStatus", "data": { "ticketId": "${ticket.id}" } }
  ]
}

The Adaptive Cards Designer (adaptivecards.io/designer) lets you paste sample data alongside a template and preview exactly how it renders in the Teams host, catching schema-version incompatibilities (like an unsupported element in 1.5) before you ship the JSON to production.

Not all Adaptive Card elements and versions are supported identically across hosts — a card that renders perfectly in the Designer's generic preview can render differently, or drop unsupported elements, inside actual Teams desktop, web, or mobile clients. Always test cards in the real Teams client, especially mobile, before shipping.

  • An Adaptive Card is declarative JSON with a body (layout elements) and actions (buttons), rendered by the host app.
  • Teams supports up to Adaptive Card schema version 1.5 with partial 1.6 support.
  • Input elements (Input.Text, Input.ChoiceSet, etc.) contribute keyed values to the data object on submit.
  • Action.Execute allows a bot to refresh the card in place, enabling multi-step wizards without a task module.
  • The Adaptive Card Templating SDK separates static layout from per-record data using ${} bindings.
  • Cards are sent from a bot as attachments with contentType application/vnd.microsoft.card.adaptive.
  • Always test rendering in the actual Teams client (including mobile), since host support for elements varies.

Practice what you learned

Was this page helpful?

Topics covered

#Microsoft365#MicrosoftTeamsDevelopmentStudyNotes#MicrosoftTechnologies#AdaptiveCards#Adaptive#Cards#Anatomy#Card#StudyNotes#SkillVeris