Spectre.Console

A library for creating beautiful console applications for .NET. Provides rich tables, charts, and prompts.

csharpclicommand-lineuiconsole

GitHub Overview

spectreconsole/spectre.console

A .NET library that makes it easier to create beautiful console applications.

Stars10,443
Watchers82
Forks576
Created:July 21, 2020
Language:C#
License:MIT License

Topics

ansi-colorsconsoleconsole-tablesconsole-visualizationdotnetdotnet-coredotnet-standard

Star History

spectreconsole/spectre.console Star History
Data as of: 7/25/2025, 11:09 AM

Framework

Spectre.Console

Overview

Spectre.Console is a library for creating beautiful console applications for .NET. It provides rich tables, charts, and prompts, and is rapidly growing in popularity due to beautiful CLI output and interactive features. Widely adopted in modern .NET applications, it dramatically improves traditional monotonous console output.

Details

Spectre.Console is a modern library that brings rich visual experiences to console applications. It provides diverse UI elements such as text styling, tables, progress bars, charts, and interactive prompts. Available for .NET 5+, .NET Framework, and .NET Standard with cross-platform support.

Key Features

  • Rich Text Styling: Various styles including colors, bold, italic, underline
  • Table Display: Beautiful and organized table display functionality
  • Progress Bars: Single and multiple progress bar displays
  • Interactive Prompts: User interaction with selection, input, confirmation
  • Charts: Bar charts, breakdown charts, etc.
  • Layout: Layout features like panels, grids, columns
  • Live Display: Real-time display updates
  • Markup Notation: HTML-like markup for styling
  • Color Support: Rich color support and automatic color adjustment

Pros and Cons

Pros

  • Beautiful Output: Professional and visually appealing console output
  • Rich UI Elements: Various elements like tables, charts, prompts
  • Easy-to-use API: Intuitive and learnable API design
  • Cross-platform: Works on Windows, Linux, macOS
  • Performance: Fast and efficient rendering engine
  • Extensibility: Custom renderers and styles can be created
  • Active Development: Continuous feature additions and bug fixes

Cons

  • Learning Curve: Takes time to master due to rich features
  • Dependencies: Adds dependency on external libraries
  • Terminal Dependency: Some parts depend on terminal capabilities
  • Overhead: May be excessive for simple applications

Key Links

Usage Examples

Basic Text Styling

using Spectre.Console;

class Program
{
    static void Main(string[] args)
    {
        // Basic text styling
        AnsiConsole.WriteLine("Normal text");
        AnsiConsole.MarkupLine("[red]Red text[/]");
        AnsiConsole.MarkupLine("[bold blue]Bold blue text[/]");
        AnsiConsole.MarkupLine("[italic green]Italic green text[/]");
        AnsiConsole.MarkupLine("[underline yellow]Underlined yellow text[/]");

        // With background color
        AnsiConsole.MarkupLine("[white on red]White text on red background[/]");
        
        // Combined styles
        AnsiConsole.MarkupLine("[bold italic underline red]All styles applied[/]");

        // Rule for separator
        AnsiConsole.Write(new Rule("[green]Section Separator[/]"));

        // Panel for box display
        AnsiConsole.Write(
            new Panel("[yellow]This is text inside a panel[/]")
                .Header("Information Panel")
                .Border(BoxBorder.Rounded)
                .BorderColor(Color.Blue));
    }
}

Table Display

using Spectre.Console;

class Program
{
    static void Main(string[] args)
    {
        // Basic table
        var table = new Table();
        
        // Add columns
        table.AddColumn("Name");
        table.AddColumn(new TableColumn("Age").Centered());
        table.AddColumn(new TableColumn("Department").RightAligned());

        // Add rows
        table.AddRow("John Doe", "30", "Development");
        table.AddRow("Jane Smith", "25", "Sales");
        table.AddRow("Bob Johnson", "35", "Planning");

        // Set styles
        table.Border(TableBorder.Rounded);
        table.BorderColor(Color.Blue);
        table.Title("Employee List");
        table.Caption("2024 Data");

        AnsiConsole.Write(table);

        AnsiConsole.WriteLine();

        // More advanced table
        var advancedTable = new Table()
            .Border(TableBorder.Square)
            .BorderColor(Color.Red)
            .Title("[yellow]Project Progress[/]");

        advancedTable.AddColumn("[green]Project Name[/]");
        advancedTable.AddColumn(new TableColumn("[blue]Progress[/]").Centered());
        advancedTable.AddColumn(new TableColumn("[red]Status[/]").RightAligned());
        advancedTable.AddColumn("[purple]Assignee[/]");

        // Apply styles conditionally
        advancedTable.AddRow(
            "Website Renewal", 
            "[green]85%[/]", 
            "[green]In Progress[/]", 
            "John");
        
        advancedTable.AddRow(
            "Mobile App", 
            "[yellow]60%[/]", 
            "[yellow]Delayed[/]", 
            "Jane");
        
        advancedTable.AddRow(
            "API Development", 
            "[red]30%[/]", 
            "[red]At Risk[/]", 
            "Bob");

        AnsiConsole.Write(advancedTable);
    }
}

Progress Bars

using Spectre.Console;
using System;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        // Single progress bar
        await AnsiConsole.Progress()
            .StartAsync(async context =>
            {
                var task = context.AddTask("[green]Downloading file...[/]");

                while (!task.IsFinished)
                {
                    await Task.Delay(100);
                    task.Increment(2);
                }
            });

        AnsiConsole.MarkupLine("[green]Download complete![/]");
        AnsiConsole.WriteLine();

        // Multiple progress bars
        await AnsiConsole.Progress()
            .Columns(new ProgressColumn[] 
            {
                new TaskDescriptionColumn(),    // Task description
                new ProgressBarColumn(),        // Progress bar
                new PercentageColumn(),         // Percentage
                new RemainingTimeColumn(),      // Remaining time
                new SpinnerColumn(),           // Spinner
            })
            .StartAsync(async context =>
            {
                var downloadTask = context.AddTask("[blue]File Download[/]", maxValue: 100);
                var processTask = context.AddTask("[yellow]Data Processing[/]", maxValue: 50);
                var uploadTask = context.AddTask("[green]Upload[/]", maxValue: 30);

                // Simulate parallel processing
                var tasks = new[]
                {
                    SimulateWork(downloadTask, 50),
                    SimulateWork(processTask, 80),  
                    SimulateWork(uploadTask, 120)
                };

                await Task.WhenAll(tasks);
            });

        AnsiConsole.MarkupLine("[green]All processing completed![/]");
    }

    static async Task SimulateWork(ProgressTask task, int delay)
    {
        while (!task.IsFinished)
        {
            await Task.Delay(delay);
            task.Increment(1);
        }
    }
}

Interactive Prompts

using Spectre.Console;
using System;
using System.ComponentModel.DataAnnotations;

class Program
{
    static void Main(string[] args)
    {
        AnsiConsole.MarkupLine("[bold blue]User Information Input[/]");
        AnsiConsole.WriteLine();

        // Text input
        var name = AnsiConsole.Ask<string>("Please enter your name:");

        // Password input (masked)
        var password = AnsiConsole.Prompt(
            new TextPrompt<string>("Please enter password:")
                .PromptStyle("red")
                .Secret());

        // Numeric input (with validation)
        var age = AnsiConsole.Prompt(
            new TextPrompt<int>("Please enter your age:")
                .PromptStyle("green")
                .ValidationErrorMessage("[red]Please enter a valid number[/]")
                .Validate(age =>
                {
                    return age switch
                    {
                        <= 0 => ValidationResult.Error("[red]Age must be a positive number[/]"),
                        >= 150 => ValidationResult.Error("[red]Age is unrealistic[/]"),
                        _ => ValidationResult.Success(),
                    };
                }));

        // Selection prompt
        var department = AnsiConsole.Prompt(
            new SelectionPrompt<string>()
                .Title("Please select your department:")
                .PageSize(10)
                .MoreChoicesText("[grey](Use arrow keys to navigate, Enter to select)[/]")
                .AddChoices(new[] {
                    "Development", "Sales", "Planning", "HR", "Accounting", "Administration"
                }));

        // Multi-selection prompt
        var skills = AnsiConsole.Prompt(
            new MultiSelectionPrompt<string>()
                .Title("Please select your skills (multiple selection):")
                .NotRequired() // Not required
                .PageSize(10)
                .MoreChoicesText("[grey](Space to select/deselect, Enter to confirm)[/]")
                .InstructionsText(
                    "[grey](Space to select, arrow keys to navigate, Enter to confirm)[/]")
                .AddChoices(new[] {
                    "C#", "JavaScript", "Python", "Java", "Go", 
                    "React", "Vue.js", "Angular", "Docker", "Kubernetes"
                }));

        // Confirmation prompt
        var confirm = AnsiConsole.Confirm("Do you want to save the input?");

        // Display results
        AnsiConsole.WriteLine();
        var panel = new Panel(
            $"[bold]Name:[/] {name}\n" +
            $"[bold]Age:[/] {age}\n" +
            $"[bold]Department:[/] {department}\n" +
            $"[bold]Skills:[/] {string.Join(", ", skills)}\n" +
            $"[bold]Save:[/] {(confirm ? "[green]Yes[/]" : "[red]No[/]")}")
            .Header("Input Results")
            .Border(BoxBorder.Rounded)
            .BorderColor(Color.Green);

        AnsiConsole.Write(panel);

        if (confirm)
        {
            // Simulate save process
            AnsiConsole.Status()
                .Start("Saving data...", ctx =>
                {
                    ctx.Spinner(Spinner.Known.Star);
                    ctx.SpinnerStyle(Style.Parse("green"));
                    
                    System.Threading.Thread.Sleep(2000);
                });

            AnsiConsole.MarkupLine("[green]Data saved successfully![/]");
        }
    }
}

Charts and Live Display

using Spectre.Console;
using System;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        // Bar chart
        AnsiConsole.Write(
            new BarChart()
                .Width(60)
                .Label("[green bold underline]Sales Performance[/]")
                .CenterLabel()
                .AddItem("Jan", 12.5, Color.Yellow)
                .AddItem("Feb", 15.8, Color.Green)
                .AddItem("Mar", 10.2, Color.Red)
                .AddItem("Apr", 18.9, Color.Blue)
                .AddItem("May", 22.1, Color.Purple));

        AnsiConsole.WriteLine();

        // Breakdown chart
        AnsiConsole.Write(
            new BreakdownChart()
                .Width(100)
                .AddItem("Development", 45, Color.Red)
                .AddItem("Testing", 25, Color.Green)
                .AddItem("Design", 20, Color.Blue)
                .AddItem("Other", 10, Color.Yellow));

        AnsiConsole.WriteLine();

        // Live display example
        await AnsiConsole.Live(CreateStatusDisplay())
            .StartAsync(async context =>
            {
                for (int i = 0; i <= 100; i += 5)
                {
                    // Update display
                    context.UpdateTarget(CreateStatusDisplay(i));
                    await Task.Delay(200);
                }
            });

        AnsiConsole.MarkupLine("[green]Processing complete![/]");
    }

    static Panel CreateStatusDisplay(int progress = 0)
    {
        var grid = new Grid()
            .AddColumn()
            .AddColumn();

        grid.AddRow(
            new Panel("[bold]System Status[/]")
                .BorderColor(Color.Blue),
            new Panel($"[bold]Progress: {progress}%[/]")
                .BorderColor(Color.Green));

        // Add progress bar
        if (progress > 0)
        {
            var progressBar = new ProgressBar()
                .Value(progress)
                .MaxValue(100);
            
            grid.AddRow(
                new Panel(progressBar)
                    .Header("Processing")
                    .BorderColor(Color.Yellow),
                new Panel($"[bold]Remaining: {(100-progress)/5}s[/]")
                    .BorderColor(Color.Purple));
        }

        return new Panel(grid)
            .Header("[bold yellow]Dashboard[/]")
            .Border(BoxBorder.Double)
            .BorderColor(Color.Cyan1);
    }
}

Project File Example

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net6.0</TargetFramework>
    <Nullable>enable</Nullable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Spectre.Console" Version="0.47.0" />
    <PackageReference Include="System.Text.Json" Version="6.0.0" />
  </ItemGroup>

</Project>