MultiSelectionPrompt

Allow users to select multiple options from a list

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 : Style

Gets or sets the highlight style of the selected choice.

InstructionsText : string

Gets or sets the text that instructs the user of how to select items.

Mode : SelectionMode

Gets or sets the selection mode. Defaults to .

MoreChoicesText : string

Gets or sets the text that will be displayed if there are more choices to show.

PageSize : int

Gets or sets the page size. Defaults to 10.

Required : bool

Gets or sets a value indicating whether or not at least one selection is required.

Title : string

Gets or sets the title.

WrapAround : bool

Gets 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)