The LiveDisplay renders content that can be updated in place without scrolling the console, perfect for dashboards, real-time monitoring, and dynamic status displays.
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.
Caution
Live display is not thread safe. Using it together with other interactive components such as prompts, progress displays, or status displays is not supported.
Basic Usage
Create a live display by passing any renderable to AnsiConsole.Live(), then update it within the context.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
// 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);
}
});
See Also
- Update Content Live - Step-by-step guide
- Progress Display - Tracking task progress
- Status Display - Simple spinner animations
- Layout Widget - Complex dashboard layouts
- Reference not found: console-explanation-async-patterns - Best practices for async operations
API Reference
Represents a live display.
Constructors
LiveDisplay(IAnsiConsole console, IRenderable target)Initializes a new instance of the class.
Parameters:
console (IAnsiConsole)target (IRenderable)Properties
AutoClear
: boolGets or sets a value indicating whether or not the live display should be cleared when it's done. Defaults to false.
Cropping
: VerticalOverflowCroppingGets or sets the vertical overflow cropping strategy.
Overflow
: VerticalOverflowGets or sets the vertical overflow strategy.
Methods
Start(Action<LiveDisplayContext> action)Starts the live display.
Parameters:
action (Action<LiveDisplayContext>)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>)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)Returns:
The same instance so that multiple calls can be chained.
LiveDisplay Cropping(VerticalOverflowCropping cropping)Sets the vertical overflow cropping strategy.
Parameters:
cropping (VerticalOverflowCropping)Returns:
The same instance so that multiple calls can be chained.
LiveDisplay Overflow(VerticalOverflow overflow)Sets the vertical overflow strategy.
Parameters:
overflow (VerticalOverflow)Returns:
The same instance so that multiple calls can be chained.