Skip to main content

🔍 Search commands

Message extension search commands allow users to search external systems and insert the results of that search into a message in the form of a card.

Search command invocation locations

There are two different areas search commands can be invoked from:

  1. Compose Area
  2. Compose Box

Compose Area and Box

Screenshot of Teams with outlines around the 'Compose Box' (for typing messages) and the 'Compose Area' (the menu option next to the compose box that provides a search bar for actions and apps).

Setting up your Teams app manifest

To use search commands you have to define them in the Teams app manifest. Here is an example:

"composeExtensions": [
{
"botId": "${{BOT_ID}}",
"commands": [
{
"id": "searchQuery",
"context": [
"compose",
"commandBox"
],
"description": "Test command to run query",
"title": "Search query",
"type": "query",
"parameters": [
{
"name": "searchQuery",
"title": "Search Query",
"description": "Your search query",
"inputType": "text"
}
]
}
]
}
]

Here we are defining the searchQuery search (or query) command.

Handle submission

Handle the search query submission when the searchQuery search command is invoked.

using Microsoft.Teams.Apps.MessageExtensions;

//...

bot.OnQuery(async (context, cancellationToken) =>
{
MessageExtensionQuery? query = context.Activity.Value;
string? commandId = query?.CommandId;
string searchText = query?.Parameters?.FirstOrDefault(p => p.Name == "searchQuery")?.Value ?? "";

if (commandId == "searchQuery")
{
return CreateSearchResults(searchText);
}

return MessageExtensionResponse.CreateBuilder()
.WithType(MessageExtensionResponseTypes.Message)
.WithText("Unknown command")
.Build();
});

CreateSearchResults() method

using Microsoft.Teams.Apps.MessageExtensions;
using Microsoft.Teams.Apps.Schema;

//...

private static InvokeResponse<MessageExtensionResponse> CreateSearchResults(string query)
{
var attachments = new List<TeamsAttachment>();

for (int i = 1; i <= 5; i++)
{
// Thumbnail cards with a tap/invoke value to trigger OnSelectItem
var previewCard = new
{
title = $"Result {i}",
text = $"This is a preview of result {i} for query '{query}'.",
tap = new
{
type = "invoke",
value = new { itemIndex = i, query }
}
};

attachments.Add(TeamsAttachment.CreateBuilder()
.WithContent(previewCard)
.WithContentType(AttachmentContentTypes.ThumbnailCard)
.Build());
}

return MessageExtensionResponse.CreateBuilder()
.WithType(MessageExtensionResponseTypes.Result)
.WithAttachmentLayout(TeamsAttachmentLayouts.List)
.WithAttachments([.. attachments])
.Build();
}

To implement custom actions when a user clicks on a search result item, you can handle the select item event:

using System.Text.Json;
using Microsoft.Teams.Apps.MessageExtensions;
using Microsoft.Teams.Apps.Schema;
using Microsoft.Teams.Cards;

//...

bot.OnSelectItem(async (context, cancellationToken) =>
{
JsonElement selectedItem = context.Activity.Value;
string itemJson = JsonSerializer.Serialize(selectedItem);

var card = new AdaptiveCard
{
Body = new List<CardElement>
{
new TextBlock("Item Selected")
{
Weight = TextWeight.Bolder,
Size = TextSize.Large,
Color = TextColor.Good
},
new TextBlock("You selected the following item:") { Wrap = true },
new TextBlock(itemJson) { Wrap = true, FontType = FontType.Monospace, Separator = true }
}
};

TeamsAttachment attachment = TeamsAttachment.CreateBuilder()
.WithAdaptiveCard(JsonSerializer.SerializeToElement(card))
.Build();

return MessageExtensionResponse.CreateBuilder()
.WithType(MessageExtensionResponseTypes.Result)
.WithAttachmentLayout(TeamsAttachmentLayouts.List)
.WithAttachments(attachment)
.Build();
});

The search results include both a full adaptive card and a preview card. The preview card appears as a list item in the search command area:

Screenshot of Teams showing a message extensions search menu open with list of search results displayed as preview cards.

When a user clicks on a list item the dummy adaptive card is added to the compose box:

Screenshot of Teams showing the selected adaptive card added to the compose box.

To implement custom actions when a user clicks on a search result item, you can add the tap property to the preview card. This allows you to handle the click event with custom logic:

Resources