# Adaptive Cards for Rich Copilot Responses **Last updated:** 2026-04 | Verified: MCP 2026-04 **Status:** GA **Category:** Copilot Extensibility & Integration --- ## Introduksjon Adaptive Cards er platform-agnostiske UI-komponenter uttrykt i JSON som lar utviklere skape rike, interaktive brukeropplevelser i Microsoft Copilot-økosystemet. De fungerer som citations og innholdsvisninger i Copilot-svar, og transformeres automatisk til native UI-elementer som tilpasser seg vertsapplikasjonens design og kontekst. **Sentral verdi:** - **Platform-agnostisk:** Én JSON-definisjon fungerer på tvers av Teams, Word, PowerPoint, Web, mobil - **Native rendering:** Adapteres automatisk til dark mode, viewport size, plattformspesifikk styling - **Declarative interactivity:** Input-felter og actions defineres i JSON, ikke custom code - **Template language:** Separate data fra presentasjon med `${}`-syntax **Bruksområder i Copilot-økosystemet:** - **M365 Copilot:** Citation cards i API plugin responses (kun via declarative agents) - **Copilot Studio:** Interactive cards med input fields, submit buttons, form validation - **Teams-integrasjoner:** Message extensions, dialogs, proactive notifications - **Power Automate:** Async proactive cards til brukere via Teams **Viktig begrensning (Verified):** I M365 Copilot er API plugins *kun* støttet som actions innenfor declarative agents. De er ikke tilgjengelig direkte i M365 Copilot. --- ## Kjernekomponenter ### Schema og versjonering | Schema-versjon | Support status | Begrensninger | |----------------|----------------|---------------| | **1.5** | GA, anbefalt for Teams/Omnichannel | Ikke `Action.Execute` i Teams | | **1.6** | GA for Web Chat / Copilot Studio test | Web Chat støtter ikke `Action.Execute` | | **1.3-1.4** | Legacy, men støttet | Mangler nyere features (labels, validation) | **Verified:** Copilot Studio renderer kun 1.6-cards i test chat, ikke på canvas. Teams og Dynamics 365 live chat widget er begrenset til 1.5. **JSON-struktur:** ```json { "type": "AdaptiveCard", "$schema": "http://adaptivecards.io/schemas/adaptive-card.json", "version": "1.5", "body": [ /* Card elements */ ], "actions": [ /* Action buttons */ ] } ``` ### Core elements (alle versjoner) | Element | Formål | Når bruke | |---------|--------|-----------| | `Container` | Grouping og styling av child elements | Logisk organisering, background colors | | `ColumnSet` / `Column` | Multi-kolonne layout | Side-by-side content (men unngå på mobile!) | | `TextBlock` | Formatert tekst (heading, paragraph) | Alle tekstvisninger | | `FactSet` / `Fact` | Title/value-par i tabellformat | Strukturert data (budsjett, transaksjoner) | | `Image` | Inline bilder | Logo, avatar, illustrasjoner | ### Input elements (interactive cards) | Input type | Bruksområde | Validering | |------------|-------------|-----------| | `Input.Text` | Fritekst, med regex-validering | `isRequired`, `regex`, `errorMessage` | | `Input.Number` | Numeriske verdier | Min/max bounds | | `Input.Date` / `Input.Time` | Dato/tid-velgere | Native platform pickers | | `Input.ChoiceSet` | Single/multi-select dropdowns | `choices` array, `style: "filtered"` for søk | | `Input.Toggle` | Boolean switch | Ja/Nei, On/Off | **Ny i 1.3+:** `label`-property (anbefalt over `placeholder`), `isRequired`, `errorMessage` for inline validation. ### Actions | Action type | Oppførsel | Bruksområde | |-------------|-----------|-------------| | `Action.Submit` | Send input data til backend | Form submission i Copilot Studio | | `Action.OpenUrl` | Åpne URL i browser | "Read more", "View in app" | | `Action.Execute` (1.5+) | Invoke backend + update card | Inline editing i M365 Copilot (preview) | | `Action.ShowCard` | Vis child card inline | Multi-step wizards | **Viktig (Verified):** Ved `Action.OpenUrl` må domenet være i `validDomains` i app manifest, ellers viser Teams "URL may lead to untrusted content". --- ## Arkitekturmønstre ### Mønster 1: Static templates (API plugins) **Når bruke:** - API returnerer alltid samme object type - Card layout sjelden endres - Enklest å vedlikeholde **Definisjon i plugin manifest:** ```json { "functions": [{ "name": "GetBudgets", "capabilities": { "response_semantics": { "data_path": "$", "properties": { "title": "$.name", "subtitle": "$.availableFunds" }, "static_template": { "type": "AdaptiveCard", "version": "1.5", "body": [{ "type": "Container", "$data": "${$root}", "items": [ { "type": "TextBlock", "text": "Name: ${if(name, name, 'N/A')}", "wrap": true }, { "type": "TextBlock", "text": "Available funds: ${if(availableFunds, formatNumber(availableFunds, 2), 'N/A')}", "wrap": true } ] }] } } } }] } ``` **Template language-funksjoner:** - `${propertyName}` – Data binding - `${if(condition, trueValue, falseValue)}` – Conditional rendering - `${formatNumber(value, decimals)}` – Number formatting - `${$root}` – Escape til root scope ### Mønster 2: Dynamic templates (API plugins) **Når bruke:** - API returnerer flere object types (f.eks. debit/credit transactions) - Different layouts per type - Template selection via JSONPath **Plugin manifest:** ```json { "name": "GetTransactions", "capabilities": { "response_semantics": { "data_path": "$.transactions", "properties": { "template_selector": "$.displayTemplate" } } } } ``` **API response:** ```json { "transactions": [ { "amount": -2000, "budgetName": "Lobby renovation", "displayTemplate": "$.templates.debit" }, { "amount": 5000, "budgetName": "Lobby renovation", "displayTemplate": "$.templates.credit" } ], "templates": { "debit": { /* AdaptiveCard JSON */ }, "credit": { /* AdaptiveCard JSON */ } } } ``` **Verified:** `template_selector` bruker JSONPath (`$.displayTemplate`) som peker til template-objektet i samme response. ### Mønster 3: Hybrid (static + dynamic) Static template fungerer som fallback hvis `template_selector` ikke finnes eller ikke matcher. ### Mønster 4: Power Fx dynamic cards (Copilot Studio) **Når bruke:** - Copilot Studio agents som trenger runtime-variabler - Dynamisk innhold fra topic/agent context **Advarsel (Verified):** Når du switcher fra JSON til Power Fx i Copilot Studio, kan du *ikke* tilbake til JSON. Lagre original JSON som kommentar! **Eksempel Power Fx:** ```power { type: "AdaptiveCard", version: "1.5", body: [ { type: "TextBlock", text: Topic.Title, // Variable reference weight: "Bolder" } ] } ``` ### Mønster 5: Inline editing med Action.Execute (preview) **Status:** Preview i M365 Copilot declarative agents **Krever:** Schema 1.5+ **Use case:** Brukeren kan editere card-data via modal dialog uten å forlate Copilot-grensesnittet. **JSON:** ```json { "type": "Action.Execute", "title": "Edit", "verb": "editItem", "data": { "itemId": "123" } } ``` Backend mottar POST med verb + data, returnerer oppdatert card. --- ## Beslutningsveiledning ### Når bruke Adaptive Cards i Copilot | Scenario | Bruk Adaptive Card? | Alternativ | |----------|---------------------|------------| | M365 Copilot API plugin citation | ✅ Ja (eneste måte) | N/A | | Copilot Studio form input | ✅ Ja (interactive card node) | Question node (enklere, men mindre fleksibel) | | Copilot Studio read-only visning | ⚠️ Nei, bruk Message node med card | Adaptive Card node krever submit button | | Power Automate proactive Teams-melding | ✅ Ja | Plain text (mindre engaging) | | Teams message extension | ✅ Ja | Hero card (mindre fleksibel) | ### Responsive design-prinsipper (Verified) **Problem:** Adaptive Cards må fungere på desktop, web, mobile, Word, PowerPoint med varierende viewport widths. **Best practices (fra M365 Copilot docs):** | Prinsipp | Do | Don't | |----------|-----|-------| | Layout | Single-column layout | Multi-column (bryter på mobile) | | Text + image | Separate rows | Same row (unntatt små ikoner/avatars) | | Width | Auto-resize via viewport | Fixed width | | Testing | Test i Teams, Word, PowerPoint, både expanded/collapsed | Bare test i én surface | **Praktisk:** Unngå `ColumnSet` hvis mulig. Bruk `Container` med vertikal stacking. ### Validation-strategi | Scenario | Teknikk | Eksempel | |----------|---------|----------| | Required fields | `isRequired: true` + `errorMessage` | `"errorMessage": "Please enter your name"` | | Format validation | `regex` property på Input.Text | `"regex": "^[A-Z][a-z]+, [A-Z][a-z]+$"` | | Conditional submit | `conditionallyEnabled: true` (1.5+) | Submit button disabled until required fields filled | | Retry logic | Copilot Studio `How many reprompts` | Default: 2 retries | ### Submit button anti-pattern (Copilot Studio) **Problem (Verified):** Adaptive Cards tillater multiple submits. Ved consecutive cards kan bruker submitte på feil card. **Løsning:** 1. **`actionSubmitId` i data payload:** Inkluder unik identifikator i submit action data (f.eks. `"actionSubmitId": "booking_confirm_card_v3_confirm"`) for å skille mellom cards 2. **Unique IDs:** Hver submit action må ha unik `id` 3. **Event handling logic:** Valider `actionSubmitId` fra response for å identifisere korrekt card 4. **Web Chat UX:** Deaktiver submit-knapper etter første klikk for å hindre stale submissions 5. **Logging:** Debug sequence av submissions --- ## Integrasjon med Microsoft-stakken ### M365 Copilot + API plugins | Komponent | Rolle | |-----------|-------| | **Declarative agent** | Container for API plugin | | **API plugin manifest** | Definerer `response_semantics` + templates | | **Backend API** | Returnerer JSON data (+ optional dynamic templates) | | **Adaptive Card** | Renderes som citation i Copilot response | **Flow:** 1. Bruker spør Copilot 2. Copilot invokerer API plugin function 3. API returnerer JSON data 4. M365 Copilot matcher data mot template (static/dynamic) 5. Adaptive Card renderes som citation med "Read more" action **Begrensning:** API plugins er *kun* tilgjengelig i declarative agents, ikke standalone i M365 Copilot. ### Copilot Studio | Node type | Interactive? | Use case | |-----------|--------------|----------| | **Adaptive Card** node | ✅ Ja (requires submit button) | Form input, multi-field data collection | | **Message** node + card | ❌ Nei (display only) | Read-only information | | **Question** node + card | ❌ Nei (display only) | Information med enkel Yes/No follow-up | **Built-in designer:** Copilot Studio inkluderer drag-and-drop card designer. Alternativt: JSON payload editor eller Power Fx formula mode. **Output variables:** Automatisk generert fra input IDs. Kan manuelt redigeres via "Edit Schema". **Retry handling:** - User sender text istedenfor submit → invalid response → retry (default: 2x) - `Allow switching to another topic`: Default ON – tillater interruptions ### Power Automate proactive messaging **Use case:** Send Adaptive Card til Teams-bruker fra inactive conversation (f.eks. approval request, notification). **Actions tilgjengelig:** - `Post message in a chat or channel` — send enkel tekst- eller card-melding - `Post adaptive card in a chat or channel` — send card uten å vente på svar - `Post adaptive card and wait for a response` — send card og vent på brukerens valg **Config:** - Post as: `Microsoft Copilot Studio agent` - Post in: `Chat with agent` - Recipient: User email/ID - Agent: Copilot Studio agent **Proaktive meldinger til grupper:** - Send til teammates via Teams connector → Get a team → List group members - Send til sikkerhetsgruppe via Microsoft Entra ID connector → Get group members - Parallell utsending: Bruk Concurrency control i Apply to each (hensyn til throttling-grenser) **Response handling:** `submitActionId` fra dynamic content = user's choice (title of Action.Submit). **Template limitation (Verified):** Power Automate støtter ikke Adaptive Cards templating feature. **Viktige begrensninger:** - Mottaker må ha installert agenten i Teams - Proaktive meldinger vises ikke i conversation transcripts eller analytics - Meldinger må være i samme environment som Power Automate flow ### Teams **Schema support:** 1.5 (ikke `Action.Execute`) **Host config:** Teams definerer colors, spacing, font sizes via HostConfig. Cards adapterer automatisk. **validDomains:** Obligatorisk for `Action.OpenUrl` – liste domener i app manifest. --- ## Offentlig sektor (Norge) ### Compliance-betraktninger | Krav | Adaptive Card-implikasjon | |------|---------------------------| | **Personvern (GDPR)** | Ikke inkluder PII i card-payloads som logges. Bruk IDs, ikke navn/fødselsnummer. | | **Universell utforming (WCAG 2.1 AA)** | Bruk `label` property (ikke `placeholder`), test med screen readers. | | **Språk** | Norsk UI-tekst i cards. Bruk template language for oversettelse hvis nødvendig. | | **Sikkerhet** | Valider all input server-side. `regex` i card er UX, ikke security. | ### Tilgjengelighet (Verified) **`label` vs `placeholder` (1.3+):** - **Do:** Bruk `label` property – renderes som persistent label med required indicator (`*`) - **Don't:** Bruk `placeholder` – dårlig color contrast, ikke lest av screen readers, forsvinner ved input **Proximity:** `label` property sikrer at label og input er visuelt koblet (viktig for screen magnifiers). **Required indicator:** Defineres i HostConfig (default: asterisk). Automatisk vist ved `isRequired: true`. ### Norsk UX-praksis **Dato-format:** `Input.Date` renderer native picker (automatisk DD.MM.YYYY i norsk locale). **Valuta:** Bruk `formatNumber()` med 2 desimaler. Prefikser med "NOK" eller "kr" i TextBlock. **Tone:** Norsk forvaltningstekst skal være klar, kortfattet, ikke-teknisk. Unngå "Submit", bruk "Send inn", "Bekreft". --- ## Kostnad og lisensiering ### Lisensavhengighet per Copilot-platform | Platform | Lisenskrav | Notes | |----------|------------|-------| | **M365 Copilot** | M365 Copilot license | Adaptive Cards i API plugins inkludert | | **Copilot Studio** | Copilot Studio capacity (per conversation) | Cards teller som én interaction | | **Teams** | M365 E3/E5 eller Teams Essentials | Native Teams apps, ingen Copilot license | | **Power Automate** | Power Automate per-user/per-flow license | Proactive cards via Teams connector | **Kostnadsoptimalisering:** - Adaptive Cards i seg selv har ingen ekstra kostnad – de er del av host platform pricing - Copilot Studio: Minimize retries (default 2x kan 3x conversation cost ved feil) - M365 Copilot: API plugin calls teller mot Copilot usage, ikke ekstra for card rendering ### Utvikling og vedlikehold | Aktivitet | Kostnadsdrivere | |-----------|-----------------| | **Initial design** | Designer-tid (bruk Adaptive Card Designer for rask prototyping) | | **Backend integration** | API-utvikling for data + template selection logic | | **Testing** | Cross-platform testing (Teams, Word, PowerPoint, mobile) | | **Versjonering** | Schema upgrades (1.5 → 1.6) kan kreve retesting | **Baseline:** Adaptive Cards er gratis open-source schema. Kostnad = host platform + utviklingstid. --- ## For arkitekten (Cosmo) ### Anbefalinger ved arkitektursamtaler **Når kunden sier:** "Vi trenger rike svar fra Copilot" **Spør:** - Hvilken Copilot? (M365, Studio, Teams) - Interactive (input) eller read-only? - Hvilke devices/surfaces? (mobile-first → single-column) **Når kunden sier:** "API plugin returnerer kompleks data" **Foreslå:** - Static template hvis data-struktur er konsistent - Dynamic templates hvis multiple object types - FactSet for strukturert data (bedre enn mange TextBlocks) **Når kunden sier:** "Brukerne skal kunne editere Copilot-svar" **Sjekk:** - Er dette M365 Copilot? → Action.Execute (preview) - Er dette Copilot Studio? → Bruk Adaptive Card node med Input fields - Vurder UX: inline edit vs new topic/dialog ### Arkitektur-patterns | Pattern | Når anbefale | |---------|--------------| | **Citation cards (M365)** | Kunde har enterprise data i backend APIs som Copilot skal vise | | **Approval workflows (Studio + PA)** | Async approvals via Teams proactive cards | | **Multi-step forms (Studio)** | Complex data collection (bruk Action.ShowCard for wizards) | | **Dashboard snippets (Teams)** | Regular status updates via bot-initiated cards | ### Fallgruver å unngå | Fallgruve | Impact | Løsning | |-----------|--------|---------| | Multi-column layout uten mobile testing | Brukere på mobil ser broken layout | Always single-column, eller test rigorously | | Hardkodet PII i templates | GDPR-brudd | Bruk IDs, fetch sensitive data on-demand | | Action.OpenUrl uten validDomains | "Untrusted content" warning i Teams | Add domains til app manifest | | Power Fx uten JSON backup | Kan ikke revertere design | Save JSON as comment før switch | | For mange Input fields | User fatigue, høy abandon rate | Split i multiple cards (Action.ShowCard) | ### Design-prinsipper (KTG-tilpasset) **Offentlig sektor Norge:** - Norsk språk i alle UI-elementer - Tydelig required-indikatorer (`isRequired: true`) - Error messages på norsk (`"errorMessage": "Vennligst fyll ut feltet"`) - Test med Jaws/NVDA screen readers **Vibe-coding-vennlig:** - Bruk Adaptive Card Designer for rapid prototyping - Export JSON, paste i plugin manifest - Test i Copilot Studio test chat før production - Iterer basert på bruker-feedback (cards er lett å endre) ### Verifikasjon og testing **Pre-deployment checklist:** - [ ] Schema version matcher host (Teams = 1.5, Studio = 1.6 for test) - [ ] Testet i alle target surfaces (Teams desktop, web, mobile) - [ ] validDomains inkluderer alle Action.OpenUrl targets - [ ] Ingen PII i card payloads (kun i backend API) - [ ] Labels, ikke placeholders - [ ] Error messages på norsk - [ ] Single-column layout (eller testet multi-column på mobile) **Runtime monitoring:** - Copilot Studio: Analytics → se abandonment rate på Adaptive Card nodes - M365 Copilot: Usage analytics → track citation engagement - Power Automate: Flow run history → se submit responses --- ## Kilder og verifisering **Verified (MCP microsoft-learn):** - API plugins kun støttet i declarative agents (ikke standalone M365 Copilot): [Adaptive Card response templates for API plugins](https://learn.microsoft.com/en-us/microsoft-365-copilot/extensibility/api-plugin-adaptive-cards) - Copilot Studio schema support (1.6 test, 1.5 Teams/Omnichannel): [Ask with Adaptive Cards](https://learn.microsoft.com/en-us/microsoft-copilot-studio/authoring-ask-with-adaptive-card) - validDomains requirement for Action.OpenUrl: [API plugin adaptive cards](https://learn.microsoft.com/en-us/microsoft-365-copilot/extensibility/api-plugin-adaptive-cards#using-static-and-dynamic-templates-together) - Responsive design best practices: [Ensure responsive Adaptive Cards across Microsoft 365 Copilot hubs](https://learn.microsoft.com/en-us/microsoft-365-copilot/extensibility/api-plugin-adaptive-cards#ensure-responsive-adaptive-cards-across-microsoft-365-copilot-hubs) - Power Fx warning (no revert to JSON): [Use Power Fx to make your card dynamic](https://learn.microsoft.com/en-us/microsoft-copilot-studio/authoring-ask-with-adaptive-card#use-power-fx-to-make-your-card-dynamic) - Submit button anti-pattern: [Submit button behavior for agents with consecutive cards](https://learn.microsoft.com/en-us/microsoft-copilot-studio/authoring-ask-with-adaptive-card#submit-button-behavior-for-agents-with-consecutive-cards) - Label vs placeholder accessibility: [Input Validation - Labels](https://learn.microsoft.com/en-us/adaptive-cards/authoring-cards/input-validation#labels) - Action.Execute preview: [Allow inline editing of Adaptive Card responses](https://learn.microsoft.com/en-us/microsoft-365-copilot/extensibility/adaptive-card-edits) - Power Automate proactive cards: [Send proactive Microsoft Teams messages](https://learn.microsoft.com/en-us/microsoft-copilot-studio/advanced-proactive-message#send-a-proactive-adaptive-card) - actionSubmitId for consecutive cards: [Submit button behavior](https://learn.microsoft.com/en-us/microsoft-copilot-studio/authoring-ask-with-adaptive-card#use-a-submit-identifier-in-actionsubmit-data) - Validation guidelines for agents: [Validation guidelines for agents - Adaptive Card response](https://learn.microsoft.com/en-us/microsoftteams/platform/concepts/deploy-and-publish/appsource/prepare/review-copilot-validation-guidelines#adaptive-card-response) **Verified (MCP code samples):** - Static template JSON structure: [Build API plugins TypeSpec](https://learn.microsoft.com/en-us/microsoft-365-copilot/extensibility/build-api-plugins-typespec#add-an-adaptive-card-to-a-get-operation) - Interactive actions card: [WhatsApp agents](https://learn.microsoft.com/en-us/microsoft-copilot-studio/publication-add-bot-to-whatsapp#use-supported-adaptive-cards-in-your-agents-topics) - Template language basics: [Adaptive Cards templating](https://learn.microsoft.com/en-us/adaptive-cards/templating/#template-language) **Baseline (Model knowledge, Jan 2025):** - Adaptive Cards general schema: https://adaptivecards.io/ - Adaptive Card Designer: https://adaptivecards.io/designer/ - JSONPath syntax for template_selector - Cross-platform rendering principles **MCP calls:** 3 docs_search, 2 docs_fetch, 1 code_sample_search **Unique URLs:** 12 Microsoft Learn documentation pages **Confidence:** Verified (all core claims backed by MCP sources)