The MultiSelectionPrompt creates interactive checkbox-style lists where users can select multiple options using the spacebar to toggle selections and enter to confirm.
When to Use
Use MultiSelectionPrompt when you need to allow users to select multiple items from a list. Common scenarios:
- Feature selection: Enable multiple application features, plugins, or modules
- Batch operations: Select multiple files, records, or items for processing
- Permission configuration: Grant multiple permissions or roles to a user
- Multi-target deployment: Choose multiple environments or servers for deployment
For single-item selection, use SelectionPrompt instead.
Basic Usage
Create a multi-selection prompt by specifying the type and adding choices. Users navigate with arrow keys, toggle selections with spacebar, and confirm with enter. The result is a List<T> of selected items.
public static void BasicMultiSelectionPromptExample()
{
var selected = AnsiConsole.Prompt(
new MultiSelectionPrompt<string>()
.Title("Which [green]features[/] do you want to enable?")
.AddChoices("Logging", "Caching", "Compression", "Authentication"));
AnsiConsole.WriteLine("You selected:");
foreach (var item in selected)
{
AnsiConsole.WriteLine($"- {item}");
}
}
Adding Choices
Bulk Adding with AddChoices
Use AddChoices() to add multiple options at once from a collection.
public static void AddChoicesExample()
{
var availablePlugins = new[]
{
"Email Notifications",
"SMS Alerts",
"Slack Integration",
"Discord Webhooks",
"Teams Connector",
"PagerDuty"
};
var selected = AnsiConsole.Prompt(
new MultiSelectionPrompt<string>()
.Title("Select [green]notification plugins[/] to install:")
.AddChoices(availablePlugins));
AnsiConsole.MarkupLine($"[blue]Installing {selected.Count} plugin(s)...[/]");
}
Grouped Choices
Use AddChoiceGroup() to organize related choices into labeled sections, making it easier for users to understand the structure of available options.
public static void GroupedChoicesExample()
{
var selected = AnsiConsole.Prompt(
new MultiSelectionPrompt<string>()
.Title("Select [green]components[/] to install:")
.AddChoiceGroup("Frontend", new[] { "React UI", "Vue UI", "Angular UI" })
.AddChoiceGroup("Backend", new[] { "REST API", "GraphQL API", "WebSockets" })
.AddChoiceGroup("Database", new[] { "PostgreSQL", "MySQL", "MongoDB" }));
AnsiConsole.WriteLine("Selected components:");
foreach (var component in selected)
{
AnsiConsole.WriteLine($"- {component}");
}
}
Pre-Selecting Items
Use Select() to mark specific items as checked by default. This is useful when you want to suggest recommended options while still allowing users to customize their selection.
public static void PreSelectItemsExample()
{
var selected = AnsiConsole.Prompt(
new MultiSelectionPrompt<string>()
.Title("Which [green]files[/] do you want to include?")
.AddChoices("README.md", "LICENSE", "CHANGELOG.md", ".gitignore", "docs/")
.Select("README.md")
.Select("LICENSE"));
AnsiConsole.WriteLine("Files to include:");
foreach (var file in selected)
{
AnsiConsole.WriteLine($"- {file}");
}
}
Selection Requirements
Required Selections
Use Required() to enforce that users must select at least one item before they can confirm. Use NotRequired() to allow an empty selection (no items checked).
public static void RequiredSelectionExample()
{
// Required: User must select at least one
var requiredSelection = AnsiConsole.Prompt(
new MultiSelectionPrompt<string>()
.Title("Select at least [red]one[/] export format:")
.Required()
.AddChoices("PDF", "CSV", "JSON", "XML"));
// Not required: User can select none
var optionalSelection = AnsiConsole.Prompt(
new MultiSelectionPrompt<string>()
.Title("Select [green]optional[/] post-processing steps:")
.NotRequired()
.AddChoices("Validate data", "Send email", "Archive results"));
AnsiConsole.MarkupLine($"[blue]Required selections: {requiredSelection.Count}[/]");
AnsiConsole.MarkupLine($"[blue]Optional selections: {optionalSelection.Count}[/]");
}
Hierarchical Choices
Creating Hierarchies
Use AddChild() to create nested tree structures with parent and child items. This is ideal for organizing permissions, file systems, or any hierarchical data.
public static void HierarchicalChoicesExample()
{
var prompt = new MultiSelectionPrompt<string>()
.Title("Select [green]permissions[/] to grant:");
prompt.AddChoice("Admin");
prompt.AddChoice("Users")
.AddChild("View Users")
.AddChild("Create Users")
.AddChild("Delete Users");
prompt.AddChoice("Content")
.AddChild("View Content")
.AddChild("Edit Content")
.AddChild("Publish Content");
var selected = AnsiConsole.Prompt(prompt);
AnsiConsole.WriteLine("Granted permissions:");
foreach (var permission in selected)
{
AnsiConsole.WriteLine($"- {permission}");
}
}
Selection Modes
The Mode() method controls which items in a hierarchy can be selected:
Leaf Mode (Default): Only leaf nodes (items without children) can be selected. Use this when you want users to select specific items, not categories.
public static void SelectionModeLeafExample()
{
var prompt = new MultiSelectionPrompt<string>()
.Title("Select [green]specific files[/] to backup:")
.Mode(SelectionMode.Leaf); // Only leaf nodes (files) can be selected
prompt.AddChoice("Documents")
.AddChild("report.pdf")
.AddChild("notes.txt");
prompt.AddChoice("Photos")
.AddChild("vacation.jpg")
.AddChild("family.jpg");
var selected = AnsiConsole.Prompt(prompt);
AnsiConsole.WriteLine("Files to backup:");
foreach (var file in selected)
{
AnsiConsole.WriteLine($"- {file}");
}
}
Independent Mode: Any node can be selected, whether it has children or not. Use this when selecting a parent folder should be different from selecting all its contents.
public static void SelectionModeIndependentExample()
{
var prompt = new MultiSelectionPrompt<string>()
.Title("Select [green]folders or individual files[/]:")
.Mode(SelectionMode.Independent); // Any node can be selected
prompt.AddChoice("src")
.AddChild("main.cs")
.AddChild("config.json");
prompt.AddChoice("tests")
.AddChild("unit-tests.cs")
.AddChild("integration-tests.cs");
var selected = AnsiConsole.Prompt(prompt);
AnsiConsole.WriteLine("Selected items:");
foreach (var item in selected)
{
AnsiConsole.WriteLine($"- {item}");
}
}
Pagination and Navigation
Page Size
Use PageSize() to control how many items are visible at once. This improves readability for long lists by showing a scrollable window.
public static void PageSizeExample()
{
var frameworks = new[]
{
".NET 6", ".NET 7", ".NET 8", ".NET 9",
"Java 17", "Java 21",
"Python 3.9", "Python 3.10", "Python 3.11", "Python 3.12",
"Node 18", "Node 20", "Node 22",
"Go 1.20", "Go 1.21", "Go 1.22"
};
var selected = AnsiConsole.Prompt(
new MultiSelectionPrompt<string>()
.Title("Select [green]supported runtimes[/]:")
.PageSize(5) // Show 5 items at a time
.AddChoices(frameworks));
AnsiConsole.MarkupLine($"[blue]Selected {selected.Count} runtime(s)[/]");
}
Wrap Around Navigation
Use WrapAround() to enable circular navigation where pressing down on the last item jumps to the first item, and pressing up on the first item jumps to the last.
public static void WrapAroundExample()
{
var selected = AnsiConsole.Prompt(
new MultiSelectionPrompt<string>()
.Title("Select [green]build configurations[/]:")
.WrapAround() // Pressing down on last item goes to first
.AddChoices("Debug", "Release", "Staging", "Production"));
AnsiConsole.WriteLine("Build configurations:");
foreach (var config in selected)
{
AnsiConsole.WriteLine($"- {config}");
}
}
Styling
Highlight Style
Use HighlightStyle() to customize the appearance of the currently focused item with colors and text decorations.
public static void HighlightStyleExample()
{
var selected = AnsiConsole.Prompt(
new MultiSelectionPrompt<string>()
.Title("Select [green]log levels[/] to enable:")
.HighlightStyle(new Style(Color.Yellow, decoration: Decoration.Bold))
.AddChoices("Trace", "Debug", "Information", "Warning", "Error", "Critical"));
AnsiConsole.WriteLine("Enabled log levels:");
foreach (var level in selected)
{
AnsiConsole.WriteLine($"- {level}");
}
}
Custom Instructions
Use InstructionsText() and MoreChoicesText() to provide clearer guidance to users about how to interact with the prompt.
public static void CustomInstructionsExample()
{
var selected = AnsiConsole.Prompt(
new MultiSelectionPrompt<string>()
.Title("Select [green]modules[/] to load:")
.InstructionsText("[grey](Press [blue]<space>[/] to toggle, [green]<enter>[/] to confirm)[/]")
.MoreChoicesText("[grey](Move up and down to see more modules)[/]")
.PageSize(3)
.AddChoices("Core", "Security", "Analytics", "Reporting", "Integration", "Automation"));
AnsiConsole.WriteLine("Modules to load:");
foreach (var module in selected)
{
AnsiConsole.WriteLine($"- {module}");
}
}
Using Custom Types
Custom Display with UseConverter
Use UseConverter() to control how complex objects are displayed in the prompt while still working with the actual object type in your code.
public static void UseConverterExample()
{
var environments = new Dictionary<string, string>
{
{ "dev", "Development (localhost)" },
{ "qa", "Quality Assurance (qa.example.com)" },
{ "stage", "Staging (staging.example.com)" },
{ "prod", "Production (example.com)" }
};
var selected = AnsiConsole.Prompt(
new MultiSelectionPrompt<string>()
.Title("Select [green]deployment targets[/]:")
.UseConverter(key => environments[key])
.AddChoices(environments.Keys));
AnsiConsole.WriteLine("Deploying to:");
foreach (var env in selected)
{
AnsiConsole.WriteLine($"- {env}: {environments[env]}");
}
}
Complete Custom Object Example
This example demonstrates working with custom record types, including display conversion, pre-selection, and processing the selected results.
public static void ComplexObjectExample()
{
var services = new[]
{
new CloudService("compute", "EC2 Instances", 0.10m),
new CloudService("storage", "S3 Storage", 0.023m),
new CloudService("database", "RDS Database", 0.17m),
new CloudService("cache", "ElastiCache", 0.05m),
new CloudService("cdn", "CloudFront CDN", 0.085m),
new CloudService("lambda", "Lambda Functions", 0.0000002m)
};
var selected = AnsiConsole.Prompt(
new MultiSelectionPrompt<CloudService>()
.Title("Select [green]cloud services[/] to provision:")
.UseConverter(service => $"{service.Name} (${service.HourlyRate:F3}/hr)")
.Required()
.AddChoices(services)
.Select(services[0])); // Pre-select EC2
AnsiConsole.WriteLine();
AnsiConsole.Write(new Rule("[yellow]Selected Services[/]"));
var totalCost = 0m;
foreach (var service in selected)
{
AnsiConsole.MarkupLine($"[blue]{service.Name}[/] ({service.Id})");
AnsiConsole.MarkupLine($" Rate: [green]${service.HourlyRate:F4}/hour[/]");
totalCost += service.HourlyRate;
}
AnsiConsole.WriteLine();
AnsiConsole.MarkupLine($"[bold]Estimated hourly cost: [green]${totalCost:F4}[/][/]");
AnsiConsole.MarkupLine($"[dim]Monthly estimate (730 hours): ${totalCost * 730:F2}[/]");
}
API Reference
Represents a multi selection list prompt.
Constructors
MultiSelectionPrompt`1(IEqualityComparer<T> comparer)Parameters:
comparer (IEqualityComparer<T>)Properties
Converter
: Func<T, string>Gets or sets the converter to get the display string for a choice. By default the corresponding is used.
HighlightStyle
: StyleGets or sets the highlight style of the selected choice.
InstructionsText
: stringGets or sets the text that instructs the user of how to select items.
Mode
: SelectionModeGets or sets the selection mode. Defaults to .
MoreChoicesText
: stringGets or sets the text that will be displayed if there are more choices to show.
PageSize
: intGets or sets the page size. Defaults to 10.
Required
: boolGets or sets a value indicating whether or not at least one selection is required.
Title
: stringGets or sets the title.
WrapAround
: boolGets or sets a value indicating whether the selection should wrap around when reaching the edge. Defaults to false.
Methods
IMultiSelectionItem<T> AddChoice(T item)Parameters:
item (T)T GetParent(T item)Parameters:
item (T)IEnumerable<T> GetParents(T item)Parameters:
item (T)List<T> Show(IAnsiConsole console)Parameters:
console (IAnsiConsole)Task<List<T>> ShowAsync(IAnsiConsole console, CancellationToken cancellationToken)Parameters:
console (IAnsiConsole)cancellationToken (CancellationToken)