Rich Responses with Adaptive Cards|Mastering Microsoft Teams Bots 3.2

3.2 Rich Responses with Adaptive Cards

Text is fine. Markdown is better. But if you really want your bot to shine — to feel like part of the app, not just a chat interface — you need Adaptive Cards.

Adaptive Cards are interactive UI components designed to work across Microsoft platforms, including Teams, Outlook, and Windows. They allow your bot to display structured information, gather user input, and trigger actions — all within the conversation window.

With Adaptive Cards, your bot doesn’t just talk. It presents. It invites. It guides.

3.2.1 What Is an Adaptive Card?

An Adaptive Card is a block of JSON that defines a UI layout — text, images, inputs, buttons — rendered natively by the Teams client. It’s like HTML, but optimized for conversations.

Example (very basic):


{
  "type": "AdaptiveCard",
  "body": [
    { "type": "TextBlock", "text": "Welcome!", "size": "Large" },
    { "type": "TextBlock", "text": "Please confirm you're ready to continue." }
  ],
  "actions": [
    { "type": "Action.Submit", "title": "I'm Ready", "data": { "action": "confirm" } }
  ],
  "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
  "version": "1.5"
}
  

This simple card renders a title, a description, and a button the user can click. The button triggers a payload you can handle in your bot logic.

3.2.2 Rendering a Card in Your Bot

Node.js Example:


const card = require("./cards/helloCard.json");
await context.sendActivity({ attachments: [CardFactory.adaptiveCard(card)] });
  

C# Example:


var cardJson = File.ReadAllText("Cards/HelloCard.json");
var cardAttachment = new Attachment
{
    ContentType = "application/vnd.microsoft.card.adaptive",
    Content = JsonConvert.DeserializeObject(cardJson)
};
await turnContext.SendActivityAsync(MessageFactory.Attachment(cardAttachment), cancellationToken);
  

3.2.3 Tools for Designing Adaptive Cards

Writing JSON by hand isn’t fun. Thankfully, Microsoft provides a fantastic Adaptive Card Designer. It’s a drag-and-drop tool that lets you visually build a card and export the JSON.

You can preview how the card looks in Teams mode and even simulate data binding.

3.2.4 Handling Card Submissions

When a user clicks a button like Action.Submit, Teams sends your bot an activity of type invoke. You’ll handle this just like any message:


// Node.js
this.onInvokeActivity(async (context, next) => {
  const actionData = context.activity.value;
  if (actionData.action === "confirm") {
    await context.sendActivity("Thanks for confirming!");
  }
  await next();
});
  

// C#
public override async Task OnInvokeActivityAsync(ITurnContext<InvokeActivity> context, CancellationToken token)
{
    var data = JObject.FromObject(context.Activity.Value);
    if (data["action"]?.ToString() == "confirm")
    {
        await context.SendActivityAsync("Thanks for confirming!");
    }
}
  

3.2.5 Dynamic Cards and Templates

Adaptive Cards support templating — you can define placeholders and bind real data at runtime. This is perfect for things like:

  • Showing a daily status update with dynamic task counts
  • Listing upcoming calendar events
  • Filling in the user’s name, department, or manager

Templates keep your card layouts clean and allow non-developers to edit the design without changing the logic.

3.2.6 Tips for Better UX

  • Keep cards simple and focused. One action per card is usually enough.
  • Use spacing, text weight, and separators to organize content.
  • Make sure your cards look good in both dark and light mode.
  • Include fallback text in case the card cannot render.

3.2.7 Summary

Adaptive Cards are what elevate a bot from a text box to a real user experience. They blend communication with interaction, letting your bot feel like a native part of Microsoft Teams.

In the next section, we’ll go deeper into conversation flow — how to manage multi-turn dialogs, maintain context, and build memory into your bot.

2025-04-09

Shohei Shimoda

I organized and output what I have learned and know here.