Skip to main content

Handling Multi-Step Forms

Dialogs can become complex yet powerful with multi-step forms. These forms can alter the flow of the survey depending on the user's input or customize subsequent steps based on previous answers.

Creating the Initial Dialog​

Start off by sending an initial card in the TaskFetch event.

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

//...

private static InvokeResponse<TaskModuleResponse> CreateMultiStepFormDialog()
{
var dialogCard = new AdaptiveCard
{
Body = new List<CardElement>
{
new TextBlock("This is a multi-step form")
{
Size = TextSize.Large,
Weight = TextWeight.Bolder
},
new TextInput
{
Id = "name",
Label = "Name",
Placeholder = "Enter your name",
IsRequired = true
}
},
Actions = new List<Action>
{
new SubmitAction
{
Title = "Submit",
Data = new { submissiondialogtype = "webpage_dialog_step_1" }
}
}
};

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

return TaskModuleResponse.CreateBuilder()
.WithType(TaskModuleResponseTypes.Continue)
.WithTitle("Multi-step Form Dialog")
.WithHeight("medium")
.WithWidth("medium")
.WithCard(attachment)
.Build();
}

Then in the submission handler, you can choose to continue the dialog with a different card.

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

//...

// Add these cases to the OnTaskSubmit handler switch statement
case "webpage_dialog_step_1":
var nameStep1 = GetFormValue("name") ?? "Unknown";
var nextStepCard = new AdaptiveCard
{
Body = new List<CardElement>
{
new TextBlock("Email")
{
Size = TextSize.Large,
Weight = TextWeight.Bolder
},
new TextInput
{
Id = "email",
Label = "Email",
Placeholder = "Enter your email",
IsRequired = true
}
},
Actions = new List<Action>
{
new SubmitAction
{
Title = "Submit",
Data = new { submissiondialogtype = "webpage_dialog_step_2", name = nameStep1 }
}
}
};

TeamsAttachment nextStepAttachment = TeamsAttachment.CreateBuilder()
.WithAdaptiveCard(JsonSerializer.SerializeToElement(nextStepCard))
.Build();

return TaskModuleResponse.CreateBuilder()
.WithType(TaskModuleResponseTypes.Continue)
.WithTitle($"Thanks {nameStep1} - Get Email")
.WithHeight("medium")
.WithWidth("medium")
.WithCard(nextStepAttachment)
.Build();

case "webpage_dialog_step_2":
var nameStep2 = GetFormValue("name") ?? "Unknown";
var emailStep2 = GetFormValue("email") ?? "No email";
await context.SendAsync($"Hi {nameStep2}, thanks for submitting the form! We got that your email is {emailStep2}", cancellationToken);
return TaskModuleResponse.CreateBuilder()
.WithType(TaskModuleResponseTypes.Message)
.WithMessage("Multi-step form completed successfully")
.Build();

Complete Multi-Step Form Handler​

Here's the complete example showing how to handle a multi-step form:

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

//...

teams.OnTaskSubmit(async (context, cancellationToken) =>
{
var data = context.Activity.Value?.Data as JsonElement?;
if (data == null)
{
return TaskModuleResponse.CreateBuilder()
.WithType(TaskModuleResponseTypes.Message)
.WithMessage("No data found in the activity value")
.Build();
}

var submissionType = data.Value.TryGetProperty("submissiondialogtype", out var submissionTypeObj) && submissionTypeObj.ValueKind == JsonValueKind.String
? submissionTypeObj.ToString()
: null;

string? GetFormValue(string key)
{
if (data.Value.TryGetProperty(key, out var val))
{
if (val is JsonElement element)
return element.GetString();
return val.ToString();
}
return null;
}

switch (submissionType)
{
case "webpage_dialog_step_1":
var nameStep1 = GetFormValue("name") ?? "Unknown";
var nextStepCard = new AdaptiveCard
{
Body = new List<CardElement>
{
new TextBlock("Email")
{
Size = TextSize.Large,
Weight = TextWeight.Bolder
},
new TextInput
{
Id = "email",
Label = "Email",
Placeholder = "Enter your email",
IsRequired = true
}
},
Actions = new List<Action>
{
new SubmitAction
{
Title = "Submit",
Data = new { submissiondialogtype = "webpage_dialog_step_2", name = nameStep1 }
}
}
};

TeamsAttachment nextStepAttachment = TeamsAttachment.CreateBuilder()
.WithAdaptiveCard(JsonSerializer.SerializeToElement(nextStepCard))
.Build();

return TaskModuleResponse.CreateBuilder()
.WithType(TaskModuleResponseTypes.Continue)
.WithTitle($"Thanks {nameStep1} - Get Email")
.WithHeight("medium")
.WithWidth("medium")
.WithCard(nextStepAttachment)
.Build();

case "webpage_dialog_step_2":
var nameStep2 = GetFormValue("name") ?? "Unknown";
var emailStep2 = GetFormValue("email") ?? "No email";
await context.SendAsync($"Hi {nameStep2}, thanks for submitting the form! We got that your email is {emailStep2}", cancellationToken);
return TaskModuleResponse.CreateBuilder()
.WithType(TaskModuleResponseTypes.Message)
.WithMessage("Multi-step form completed successfully")
.Build();

default:
return TaskModuleResponse.CreateBuilder()
.WithType(TaskModuleResponseTypes.Message)
.WithMessage("Unknown submission type")
.Build();
}
});