Spectre.Console.Rx
1.1.8
dotnet add package Spectre.Console.Rx --version 1.1.8
NuGet\Install-Package Spectre.Console.Rx -Version 1.1.8
<PackageReference Include="Spectre.Console.Rx" Version="1.1.8" />
<PackageVersion Include="Spectre.Console.Rx" Version="1.1.8" />
<PackageReference Include="Spectre.Console.Rx" />
paket add Spectre.Console.Rx --version 1.1.8
#r "nuget: Spectre.Console.Rx, 1.1.8"
#:package Spectre.Console.Rx@1.1.8
#addin nuget:?package=Spectre.Console.Rx&version=1.1.8
#tool nuget:?package=Spectre.Console.Rx&version=1.1.8
Spectre.Console.Rx
Reactive extensions for Spectre.Console. Compose terminal animations with Rx and keep all UI mutations on a single, deterministic scheduler.
- Reactive wrappers for Spectre.Console
Status
,Progress
, andLive
- Single-threaded UI scheduler to keep the console thread-safe
- Fluent, chainable context APIs
- Works on .NET Standard 2.0, .NET 8, and .NET 9
Visit https://spectreconsole.net for Spectre.Console docs and https://github.com/spectreconsole/spectre.console for the original source.
Packages
- Spectre.Console.Rx
- Spectre.Console.Rx.Json (optional JSON helpers)
Install:
# Core
dotnet add package Spectre.Console.Rx
# Optional JSON helpers
dotnet add package Spectre.Console.Rx.Json
Target frameworks
- .NET Standard 2.0
- .NET 8
- .NET 9
Core concept
The console is not thread-safe. Spectre.Console.Rx enforces a single UI thread via AnsiConsoleRx.Scheduler
so all reactive pipelines render on the same thread. Drive animations by pushing work to that scheduler and mark contexts finished when done.
Key points:
- Always switch to the UI scheduler:
.ObserveOn(AnsiConsoleRx.Scheduler)
- Only one console context (Status/Progress/Live) should run at a time
- Call
IsFinished()
on the context to end rendering/animation loops
Quick start
Status
using System.Reactive.Linq;
using Spectre.Console.Rx;
AnsiConsoleRx
.Status("[yellow]Initializing[/]", s => s.AutoRefresh(true))
.ObserveOn(AnsiConsoleRx.Scheduler)
.Subscribe(ctx => ctx.Schedule(async scheduler =>
{
await scheduler.Sleep(TimeSpan.FromMilliseconds(800));
ctx.Status("[blue]Warming up[/]");
ctx.Spinner(Spinner.Known.Dots);
await scheduler.Sleep(TimeSpan.FromMilliseconds(800));
ctx.Status("[green]Ready[/]");
ctx.IsFinished();
}));
Live (animate a renderable)
using System.Reactive.Linq;
using Spectre.Console.Rx;
var table = new Table().AddColumn("Col").AddRow("Row 1");
AnsiConsoleRx
.Live(table, ld => ld.AutoClear(false))
.ObserveOn(AnsiConsoleRx.Scheduler)
.Subscribe(ctx =>
{
// Chain updates in-place (blocking) for simple demos
ctx
.Update(250, () => table.AddRow("Row 2"))
.Update(250, () => table.AddRow("Row 3"))
.Update(250, () => table.AddRow("Done"));
ctx.IsFinished();
});
Progress
using System.Reactive.Linq;
using Spectre.Console.Rx;
AnsiConsoleRx
.Progress(p => p.AutoClear(false)
.Columns(new ProgressColumn[]
{
new TaskDescriptionColumn(),
new ProgressBarColumn(),
new PercentageColumn(),
new RemainingTimeColumn(),
new SpinnerColumn(),
}))
.ObserveOn(AnsiConsoleRx.Scheduler)
.Subscribe(async ctx =>
{
var t1 = ctx.AddTask("Downloading").IsIndeterminate(false);
var t2 = ctx.AddTask("Processing");
await ctx.Schedule(TimeSpan.FromMilliseconds(100), () =>
{
t1.Increment(2);
if (t1.Value >= 100) t2.Increment(4);
});
// Progress completes automatically when all started tasks are finished
});
Threading model and scheduling
AnsiConsoleRx.Scheduler
is a single-threaded scheduler. It hosts aSynchronizationContext
and processes posted work sequentially.- Use
.ObserveOn(AnsiConsoleRx.Scheduler)
in your observable pipelines before mutating UI. - Use context scheduling helpers to perform timed loops without blocking your app thread.
Context scheduling helpers
All helpers run on the Spectre scheduler and update the UI safely.
Task Schedule(this IContext context, TimeSpan delay, Func<bool> isComplete, Action action)
- Executes
action
repeatedly everydelay
untilisComplete()
returns true. Callscontext.Refresh()
after each iteration.
- Executes
Task Schedule(this IContext context, Action<SpectreConsoleScheduler> action)
- Executes an action on the scheduler. Useful to sequence async sleeps and UI updates.
Task<T> Schedule<T>(this IContext context, Func<SpectreConsoleScheduler, Task<T>> action)
- Executes an async function on the scheduler and returns its result.
Task Schedule(this IContext context, TimeSpan delay, Action action)
(ProgressContext only)- Repeats
action
everydelay
until all started progress tasks report finished.
- Repeats
The SpectreConsoleScheduler
provides Sleep(TimeSpan)
for non-blocking waits and follows IScheduler
from Rx.
API reference (most used)
AnsiConsoleRx
ISpectreConsoleScheduler Scheduler
� the UI scheduler instanceIObservable<StatusContext> Status(string status, Func<Status, Status>? configure = null)
IObservable<ProgressContext> Progress(Func<Progress, Progress>? configure = null)
IObservable<LiveDisplayContext> Live(IRenderable renderable, Func<LiveDisplay, LiveDisplay>? configure = null)
IObservable<(ProgressContext context, ProgressTask[] tasks)> AddTasks(this IObservable<ProgressContext>, Func<ProgressContext, ProgressTask[]> factory)
LiveDisplayContext Update(this LiveDisplayContext ctx, int delayMs, Action action)
� simple chained updates (demo-friendly)void IsFinished(this LiveDisplayContext ctx)
/void IsFinished(this StatusContext ctx)
� signal completion
StatusContext
- Properties:
string Status
,Spinner Spinner
,Style? SpinnerStyle
,bool IsFinished
- Methods:
void Refresh()
- Extensions:
Status(string)
,Spinner(Spinner)
,SpinnerStyle(Style?)
,IsFinished()
ProgressContext
- Properties:
bool IsFinished
- Methods:
ProgressTask AddTask(...)
,void Refresh()
,Task Schedule(TimeSpan delay, Action action)
LiveDisplayContext
- Properties:
bool IsFinished
- Methods:
void UpdateTarget(IRenderable? target)
,void Refresh()
- Extensions:
Update(int delayMs, Action)
,IsFinished()
JSON helpers (optional)
Spectre.Console.Rx.Json
adds helpers to pretty print JSON with Spectre.Console widgets.
using Spectre.Console.Rx.Json;
var panel = new Panel(new JsonText(jsonString))
.Header("Data")
.SquareBorder()
.BorderColor(Color.LightSkyBlue1);
AnsiConsole.Write(panel);
Best practices
- Only one Status/Progress/Live should be active at a time (the console is single-threaded)
- Always
.ObserveOn(AnsiConsoleRx.Scheduler)
before mutating UI - End animations with
IsFinished()
so observables complete - Prefer scheduler
Sleep
overThread.Sleep
to keep the pump responsive - Keep heavy work off the UI scheduler; compute elsewhere, then push results to UI via
ObserveOn
Troubleshooting
- Nothing renders / pipeline hangs
- Ensure
.ObserveOn(AnsiConsoleRx.Scheduler)
is applied beforeSubscribe
that updates UI - Make sure you call
IsFinished()
on the context when done
- Ensure
- Flicker or interleaved output
- Avoid running multiple contexts concurrently; sequence them
- Exceptions swallowed
- Wrap your subscription in
Subscribe(onNext, onError, onCompleted)
and logonError
- Wrap your subscription in
Examples
See example projects under src
:
LiveExample
,LiveTableExample
StatusExample
ProgressExample
CombinedExample
License
MIT License. See the LICENSE file for details.
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- system.memory (>= 4.6.3)
- System.Reactive (>= 6.0.2)
-
net10.0
- System.Reactive (>= 6.0.2)
-
net8.0
- System.Reactive (>= 6.0.2)
-
net9.0
- System.Reactive (>= 6.0.2)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Spectre.Console.Rx:
Package | Downloads |
---|---|
Spectre.Console.Rx.Json
A library that extends Spectre.Console with JSON superpowers. |
|
Spectre.Console.Rx.Testing
Contains testing utilities for Spectre.Console. |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last Updated |
---|---|---|
1.1.8 | 319 | 9/19/2025 |
1.0.82 | 383 | 3/19/2024 |
1.0.32 | 387 | 12/20/2023 |
1.0.30 | 178 | 12/20/2023 |
1.0.29 | 227 | 12/19/2023 |
1.0.27 | 240 | 11/30/2023 |
1.0.25 | 234 | 11/17/2023 |
1.0.23 | 203 | 11/5/2023 |
1.0.22 | 181 | 11/5/2023 |
1.0.20 | 227 | 10/20/2023 |
1.0.17 | 228 | 9/18/2023 |
1.0.13 | 213 | 9/11/2023 |
1.0.11 | 263 | 8/31/2023 |
1.0.10 | 226 | 8/29/2023 |
1.0.6 | 235 | 8/27/2023 |
1.0.5 | 253 | 8/26/2023 |
Compatability with Net 8 / 9 / 10 and netstandard2.0