Live Display

Update and refresh any renderable content dynamically in real-time

The LiveDisplay renders content that can be updated in place without scrolling the console, perfect for dashboards, real-time monitoring, and dynamic status displays.

Screenshot

When to Use

Use LiveDisplay when you need to update arbitrary content in place without creating new output lines. Common scenarios:

  • Custom dashboards: Display real-time metrics, server stats, or system monitors with any widget combination
  • Dynamic tables: Build tables incrementally or update existing rows as data changes
  • Status transitions: Show multi-step processes with changing panels or formatted text
  • Real-time data: Update charts, gauges, or custom visualizations continuously

For progress tracking with multiple tasks, use Progress instead. For simple spinner animations, use Status.

Basic Usage

Create a live display by passing any renderable to AnsiConsole.Live(), then update it within the context.

public static void BasicLiveDisplayExample()
{
    var table = new Table();
    table.AddColumn("Status");
    table.AddRow("Starting...");
  
    AnsiConsole.Live(table)
        .Start(ctx =>
        {
            Thread.Sleep(1000);
            table.AddRow("Processing...");
            ctx.Refresh();
  
            Thread.Sleep(1000);
            table.AddRow("Complete!");
            ctx.Refresh();
  
            Thread.Sleep(1000);
        });
}

Updating Content

Modifying Mutable Renderables

Modify properties of mutable widgets like Table, then call ctx.Refresh() to update the display.

public static void LiveDisplayWithTableExample()
{
    var table = new Table()
        .AddColumn("Server")
        .AddColumn("Status")
        .AddColumn("Uptime");
  
    AnsiConsole.Live(table)
        .Start(ctx =>
        {
            var servers = new[]
            {
                ("web-01", "[green]Online[/]", "99.9%"),
                ("web-02", "[green]Online[/]", "99.8%"),
                ("db-01", "[green]Online[/]", "100%"),
                ("cache-01", "[yellow]Degraded[/]", "95.2%"),
                ("api-01", "[green]Online[/]", "99.7%")
            };
  
            foreach (var (server, status, uptime) in servers)
            {
                table.AddRow(server, status, uptime);
                ctx.Refresh();
                Thread.Sleep(500);
            }
        });
}

Replacing the Target

Use ctx.UpdateTarget() to completely replace the displayed renderable with a different widget.

public static void LiveDisplayUpdateTargetExample()
{
    AnsiConsole.Live(new Text("Initializing..."))
        .Start(ctx =>
        {
            Thread.Sleep(1000);
  
            // Replace with a panel
            var panel = new Panel("Loading configuration...")
                .Header("Step 1")
                .BorderColor(Color.Blue);
            ctx.UpdateTarget(panel);
            Thread.Sleep(1000);
  
            // Replace with a different panel
            var panel2 = new Panel("Connecting to database...")
                .Header("Step 2")
                .BorderColor(Color.Yellow);
            ctx.UpdateTarget(panel2);
            Thread.Sleep(1000);
  
            // Replace with final panel
            var panel3 = new Panel("[green]Ready![/]")
                .Header("Complete")
                .BorderColor(Color.Green);
            ctx.UpdateTarget(panel3);
            Thread.Sleep(1000);
        });
}

Displaying Panels

Wrap dynamic content in panels for polished status displays.

public static void LiveDisplayWithPanelExample()
{
    var table = new Table()
        .Border(TableBorder.None)
        .AddColumn("Metric")
        .AddColumn("Value");
  
    var panel = new Panel(table)
        .Header("System Monitor")
        .BorderColor(Color.Cyan)
        .RoundedBorder();
  
    AnsiConsole.Live(panel)
        .Start(ctx =>
        {
            for (int i = 0; i < 10; i++)
            {
                table.Rows.Clear();
                table.AddRow("CPU Usage", $"{Random.Shared.Next(10, 80)}%");
                table.AddRow("Memory", $"{Random.Shared.Next(2, 8)} GB / 16 GB");
                table.AddRow("Network", $"{Random.Shared.Next(100, 999)} MB/s");
                table.AddRow("Uptime", $"{i + 1} seconds");
  
                ctx.Refresh();
                Thread.Sleep(1000);
            }
        });
}

Handling Overflow

When content exceeds the console height, LiveDisplay provides several overflow strategies.

Ellipsis Mode

Show an ellipsis indicator when content is truncated.

public static void LiveDisplayOverflowEllipsisExample()
{
    var table = new Table()
        .AddColumn("Line");
  
    AnsiConsole.Live(table)
        .Overflow(VerticalOverflow.Ellipsis)
        .Start(ctx =>
        {
            for (int i = 1; i <= 100; i++)
            {
                table.AddRow($"Line {i}");
                ctx.Refresh();
                Thread.Sleep(50);
            }
        });
}

Crop Mode

Silently crop content that doesn't fit, combined with cropping direction control.

public static void LiveDisplayOverflowCropExample()
{
    var table = new Table()
        .AddColumn("Line");
  
    AnsiConsole.Live(table)
        .Overflow(VerticalOverflow.Crop)
        .Start(ctx =>
        {
            for (int i = 1; i <= 100; i++)
            {
                table.AddRow($"Line {i}");
                ctx.Refresh();
                Thread.Sleep(50);
            }
        });
}

Visible Mode

Allow content to scroll naturally when it exceeds console height.

public static void LiveDisplayOverflowVisibleExample()
{
    var table = new Table()
        .AddColumn("Line");
  
    AnsiConsole.Live(table)
        .Overflow(VerticalOverflow.Visible)
        .Start(ctx =>
        {
            for (int i = 1; i <= 30; i++)
            {
                table.AddRow($"Line {i}");
                ctx.Refresh();
                Thread.Sleep(100);
            }
        });
}

Cropping Direction

Control which part of overflowing content remains visible.

Crop from Top

Keep the most recent content visible by removing old content from the top.

public static void LiveDisplayCroppingTopExample()
{
    var table = new Table()
        .AddColumn("Log Entry");
  
    AnsiConsole.Live(table)
        .Overflow(VerticalOverflow.Crop)
        .Cropping(VerticalOverflowCropping.Top)
        .Start(ctx =>
        {
            for (int i = 1; i <= 50; i++)
            {
                table.AddRow($"[dim]{DateTime.Now:HH:mm:ss}[/] Log entry {i}");
                ctx.Refresh();
                Thread.Sleep(100);
            }
        });
}

Crop from Bottom

Keep the initial content visible by removing new content from the bottom.

public static void LiveDisplayCroppingBottomExample()
{
    var table = new Table()
        .AddColumn("Task Queue");
  
    AnsiConsole.Live(table)
        .Overflow(VerticalOverflow.Crop)
        .Cropping(VerticalOverflowCropping.Bottom)
        .Start(ctx =>
        {
            for (int i = 1; i <= 50; i++)
            {
                table.AddRow($"Task {i}: Processing");
                ctx.Refresh();
                Thread.Sleep(100);
            }
        });
}

Auto Clear

Remove the live display from the console when the context completes.

public static void LiveDisplayAutoClearExample()
{
    var spinner = new Table()
        .AddColumn("Status")
        .AddRow("[blue]Processing...[/]");
  
    AnsiConsole.Live(spinner)
        .AutoClear(true)
        .Start(ctx =>
        {
            for (int i = 1; i <= 5; i++)
            {
                spinner.Rows.Clear();
                spinner.AddRow($"[blue]Processing step {i}/5...[/]");
                ctx.Refresh();
                Thread.Sleep(800);
            }
        });
  
    AnsiConsole.WriteLine("Display cleared - task complete!");
}

Async Operations

Use StartAsync() for asynchronous work within the live display context.

public static async Task LiveDisplayAsyncExample()
{
    var status = new Table()
        .AddColumn("Operation")
        .AddColumn("Status");
  
    await AnsiConsole.Live(status)
        .StartAsync(async ctx =>
        {
            var operations = new[]
            {
                "Fetching data",
                "Processing records",
                "Updating database",
                "Generating report",
                "Sending notifications"
            };
  
            foreach (var operation in operations)
            {
                status.AddRow(operation, "[yellow]In Progress[/]");
                ctx.Refresh();
  
                await Task.Delay(1000);
  
                status.Rows.Update(status.Rows.Count - 1, 1, new Text("[green]Complete[/]"));
                ctx.Refresh();
            }
        });
}

Returning Values

Return results from the live display context using the generic Start<T>() method.

public static void LiveDisplayReturnValueExample()
{
    var result = AnsiConsole.Live(new Text("Processing..."))
        .Start(ctx =>
        {
            int total = 0;
  
            for (int i = 1; i <= 10; i++)
            {
                total += i;
                ctx.UpdateTarget(new Text($"Processing: {i}/10 (Total: {total})"));
                Thread.Sleep(300);
            }
  
            ctx.UpdateTarget(new Text("[green]Complete![/]"));
            Thread.Sleep(500);
  
            return total;
        });
  
    AnsiConsole.WriteLine($"Final result: {result}");
}

Combining Widgets

Create sophisticated dashboards by combining multiple widgets in layouts.

public static void LiveDisplayCompositeExample()
{
    // Create status table
    var statusTable = new Table()
        .Border(TableBorder.Rounded)
        .BorderColor(Color.Cyan)
        .AddColumn("Service")
        .AddColumn("Status")
        .AddColumn("Requests/sec");
  
    // Create metrics table
    var metricsTable = new Table()
        .Border(TableBorder.Rounded)
        .BorderColor(Color.Yellow)
        .AddColumn("Metric")
        .AddColumn("Current")
        .AddColumn("Average");
  
    // Create layout with both tables
    var layout = new Layout("Root")
        .SplitRows(
            new Layout("Header"),
            new Layout("Body").SplitColumns(
                new Layout("Status"),
                new Layout("Metrics")
            )
        );
  
    layout["Header"].Update(
        new Panel("[bold cyan]Real-Time Dashboard[/]")
            .BorderColor(Color.Blue)
            .Padding(1, 0)
    );
  
    layout["Status"].Update(new Panel(statusTable).Header("Services"));
    layout["Metrics"].Update(new Panel(metricsTable).Header("System Metrics"));
  
    AnsiConsole.Live(layout)
        .Start(ctx =>
        {
            for (int i = 0; i < 15; i++)
            {
                // Update status table
                statusTable.Rows.Clear();
                statusTable.AddRow("API Gateway", "[green]Healthy[/]", $"{Random.Shared.Next(100, 500)}");
                statusTable.AddRow("Auth Service", "[green]Healthy[/]", $"{Random.Shared.Next(50, 200)}");
                statusTable.AddRow("Database", i > 10 ? "[yellow]Degraded[/]" : "[green]Healthy[/]", $"{Random.Shared.Next(200, 800)}");
                statusTable.AddRow("Cache", "[green]Healthy[/]", $"{Random.Shared.Next(1000, 3000)}");
  
                // Update metrics table
                metricsTable.Rows.Clear();
                metricsTable.AddRow("CPU", $"{Random.Shared.Next(20, 75)}%", "45%");
                metricsTable.AddRow("Memory", $"{Random.Shared.Next(4, 12)} GB", "8 GB");
                metricsTable.AddRow("Disk I/O", $"{Random.Shared.Next(10, 90)} MB/s", "45 MB/s");
                metricsTable.AddRow("Network", $"{Random.Shared.Next(100, 500)} MB/s", "250 MB/s");
  
                ctx.Refresh();
                Thread.Sleep(1000);
            }
        });
}

API Reference

Represents a live display.

Constructors

LiveDisplay(IAnsiConsole console, IRenderable target)

Initializes a new instance of the class.

Parameters:

console (IAnsiConsole)
The console.
target (IRenderable)
The target renderable to update.

Properties

AutoClear : bool

Gets or sets a value indicating whether or not the live display should be cleared when it's done. Defaults to false.

Cropping : VerticalOverflowCropping

Gets or sets the vertical overflow cropping strategy.

Overflow : VerticalOverflow

Gets or sets the vertical overflow strategy.

Methods

Start(Action<LiveDisplayContext> action)

Starts the live display.

Parameters:

action (Action<LiveDisplayContext>)
The action to execute.
T Start(Func<LiveDisplayContext, T> func)

Parameters:

func (Func<LiveDisplayContext, T>)
Task StartAsync(Func<LiveDisplayContext, Task> func)

Starts the live display.

Parameters:

func (Func<LiveDisplayContext, Task>)
The action to execute.

Returns:

The result.

Task<T> StartAsync(Func<LiveDisplayContext, Task<T>> func)

Parameters:

func (Func<LiveDisplayContext, Task<T>>)

Extension Methods

LiveDisplay AutoClear(bool enabled)

Sets whether or not auto clear is enabled. If enabled, the live display will be cleared when done.

Parameters:

enabled (bool)
Whether or not auto clear is enabled.

Returns:

The same instance so that multiple calls can be chained.

LiveDisplay Cropping(VerticalOverflowCropping cropping)

Sets the vertical overflow cropping strategy.

Parameters:

cropping (VerticalOverflowCropping)
The overflow cropping strategy to use.

Returns:

The same instance so that multiple calls can be chained.

LiveDisplay Overflow(VerticalOverflow overflow)

Sets the vertical overflow strategy.

Parameters:

overflow (VerticalOverflow)
The overflow strategy to use.

Returns:

The same instance so that multiple calls can be chained.