Sending Widgets
The simplest widget is static HTML with no callbacks.
The SDK build helpers take a widget payload and produce a message with the correct extendedmarkdown text format and the fenced html-widget code block already assembled.
HTML Widgets are in preview and the API surface may change. HTML Widgets are planned for public preview on 11/16.
There is a gap in the export APIs that prevents widget content from being exported. If your organization determines this is a problem, you can disable bots that may send widgets.
Building a widget message
Use buildHtmlWidgetMessage to turn a payload into a message you can send directly. The helper sets textFormat to extendedmarkdown and wraps the payload in the fenced html-widget block. You only need to provide name, html, and domain; the type defaults to widget/mcp-ui.
import { App, buildHtmlWidgetMessage } from '@microsoft/teams.apps';
const app = new App();
app.on('message', async ({ send }) => {
const message = buildHtmlWidgetMessage({
name: 'Simple Widget',
html: '<div>Hello from a widget</div>',
domain: 'https://teams.microsoft.com',
});
await send(message);
});
The examples on this page use minimal HTML to show the helpers. The SDK sends your HTML unchanged, so a widget that needs to report its size must also complete the handshake and report its height, as described in Your widget owns the handshake and sizing.
Adding text before and after
You often want to introduce a widget with a sentence, or add a note after it. The build helpers accept options for text to place before and after the widget block.
const message = buildHtmlWidgetMessage(
{
name: 'Simple Widget',
html: '<div>Hello from a widget</div>',
domain: 'https://teams.microsoft.com',
},
{
before: 'Here is a simple static widget:',
after: 'No callbacks needed for static content.',
}
);
await send(message);
Building the markdown directly
The message helper covers the common case, but it produces one complete message from a single payload. Build just the markdown string when you need to do something the message helper cannot, such as combining more than one widget in a single message, embedding a widget inside text you are already assembling, or setting activity properties the helper does not touch (for example attachments or channel data).
Remember to set the text format to extendedmarkdown so the Teams client parses the widget block.
import { buildHtmlWidgetMarkdown } from '@microsoft/teams.apps';
// buildHtmlWidgetMarkdown returns just the string, so you can compose several
// widgets into one message or splice a widget into text you already have.
const weather = buildHtmlWidgetMarkdown({
name: 'Weather',
html: '<div>Sunny, 72F</div>',
domain: 'https://teams.microsoft.com',
});
const forecast = buildHtmlWidgetMarkdown({
name: 'Forecast',
html: '<div>Rain tomorrow</div>',
domain: 'https://teams.microsoft.com',
});
await send({
type: 'message',
text: `Today:\n\n${weather}\n\nLooking ahead:\n\n${forecast}`,
textFormat: 'extendedmarkdown',
});
Interactive widget HTML
The SDK sends your HTML exactly as authored and does not inject any script into it.
Every widget must carry its own ui/initialize handshake and ui/notifications/size-changed reporting, or it will not initialize or size correctly. This is described in Your widget owns the handshake and sizing.