An opinionated, component-based UI framework for .NET console applications. Build terminal interfaces with tables, menus, progress bars, spinners, layout containers, and more.
Do note that this simple project is very limited and simple in scope compared to a more advanced notable project like Spectre.Console, so use that instead if you can. Its much better than this little library that I've made for myself.
- ๐ Features
- ๐ฆ Installation
- ๐ Usage Guide
- ๐จ Theming
- ๐๏ธ Architecture
- ๐ป Requirements
- ๐ Licence
- ๐ค Contributing
- Theming System โ Fully composable themes combining colour schemes and border styles, with built-in presets
- Semantic Colour Output โ Contextual coloured text for errors, success, warnings, and information
- Rich Components โ Tables, menus, progress bars, spinners, and notifications
- Layout Containers โ Panel, Row, Column, and Viewport for structured terminal layouts
- Renderer Abstraction โ Swap rendering backends for testing or deferred output via
IRenderer - Scoped Theming โ Apply themes globally or per-component, with scoped overrides via
ConsoleContext
dotnet add package ConsolePrism- Clone the repository
- Add a reference to your project:
dotnet add reference path/to/src/ConsolePrism.csprojusing ConsolePrism.Core;
ColorWriter.WriteSuccessLine("Operation completed!");
ColorWriter.WriteErrorLine("Something went wrong.");
ColorWriter.WriteWarningLine("Proceed with caution.");
ColorWriter.WriteInfoLine("Here is some information.");
ColorWriter.WriteHighlightLine("Important text.");
// Explicit colour when needed
ColorWriter.WriteColoredLine("Custom text", ConsoleColor.Magenta);using ConsolePrism.Components;
// Arrow-key interactive menu (default)
string[] choices = ["New Game", "Continue", "Settings", "Exit"];
Menu interactive = new("Main Menu", MenuStyle.Interactive, choices);
int choice = interactive.Interact();
// Numbered menu
Menu numbered = new("Select Difficulty", MenuStyle.Numbered, "Easy", "Normal", "Hard");
int difficulty = numbered.Interact();
// Bordered menu
Menu bordered = new("Choose Mode", MenuStyle.Bordered, "Story", "Creative", "Survival");
int mode = bordered.Interact();using ConsolePrism.Components;
string[] headers = ["Name", "Score", "Level"];
string[][] data = [
["Alice", "1250", "10"],
["Bob", "980", "8" ],
["Charlie", "1500", "12"],
]; // Can be nullable for empty cells
new Table(headers, data).Render();
// Alternatively for coloured cells
TableCell[][] colouredData = [
["Alice", new TableCell("1250", ConsoleColor.Green), "10"],
["Bob", new TableCell("980", ConsoleColor.Red), "8" ],
["Charlie", new TableCell("1500", ConsoleColor.Yellow),"12"],
];
new Table(headers, colouredData).Render();
// Custom column widths
int[] widths = [15, 10, 8];
new Table(headers, data, widths).Render();using ConsolePrism.Components;
// Static progress bar
new ProgressBar(75, "Processing", 100).Render();
// Animated in-place progress
ProgressBar bar = new(0, "Loading", 100) { InPlace = true };
for (int i = 0; i <= 100; i++)
{
bar.Current = i;
bar.Render();
Thread.Sleep(50);
}using ConsolePrism.Components;
Spinner spinner = new(Spinner.Dots, "Loading assets...");
spinner.Start();
// Do work...
await LoadAssetsAsync();
spinner.Stop("Assets loaded successfully!");
// Using Dispose pattern
using Spinner spinner = new(Spinner.Pulse, "Connecting...");
spinner.Start();
await ConnectAsync();using ConsolePrism.Components;
new Notification("File saved!", false, NotificationLevel.Success).Render();
new Notification("Low disk space.", false, NotificationLevel.Warning).Render();
new Notification("Connection failed.", false NotificationLevel.Error).Render();
// Transient notification
new Notification("Autosaving...", false, NotificationLevel.Info, 2000).Render();
// Bordered notification
new Notification("Welcome to ConsolePrism!", true, NotificationLevel.Info).Render();using ConsolePrism.Components;
// Simple text
new ConsoleText("This is a simple text component.").Render();
// Text with colour
new ConsoleText("This is an error message.", ConsoleColor.Red).Render();
// Note: This has been implemented with the sole purpose of for ease of use in the panel, column, row and viewport layouts.using ConsolePrism.Layout;
Panel simplePanel = new(
content: new ConsoleText("This is a simple panel.") // Or any component
);
// Complex panel with title, content, and padding
Panel panel = new(
title: "Welcome",
content: new ConsoleText("Hello, World!"),
horizontalPadding: 2,
verticalPadding: 1
);
panel.Render();using ConsolePrism.Layout;
Row row = new(
spacing: 1,
new ConsoleText("Header"),
new Panel(title: "Info", content: new ConsoleText("Details...")),
new ConsoleText("Footer")
);
row.Render();
// Alternatively through Fluent API:
Row fluentRow = new Row(spacing: 1)
.Add(new ConsoleText("Header"))
.Add(new Panel(title: "Info", content: new ConsoleText("Details...")))
.Add(new ConsoleText("Footer"));
fluentRow.Render();using ConsolePrism.Layout;
Viewport viewport = new(
height: 2,
new ConsoleText("Line 1"),
new ConsoleText("Line 2"),
new ConsoleText("Line 3"),
new ConsoleText("Line 4"),
new ConsoleText("Line 5")
);
viewport.Render();
// Alternatively through Fluent API:
Viewport fluentViewport = new Viewport(height: 10)
.Add(new ConsoleText("Line 1"))
.Add(new ConsoleText("Line 2"))
// ... 50+ more lines
.Add(new ConsoleText("Line 52"));
fluentViewport.Render(); // Initially shows lines 1-10
// User can scroll
fluentViewport.ScrollDown(3); // Now shows lines 4-13
fluentViewport.Render();
fluentViewport.ScrollUp(1); // Back to lines 3-12
fluentViewport.Render();
fluentViewport.ScrollToTop(); // Back to lines 1-10
fluentViewport.Render();
// Users can also interact with the viewport itself through up/down arrow keys:
fluenViewport.Interact();using ConsolePrism.Layout;
Column column = new(
gap: 2,
new Panel(title: "Left", content: new ConsoleText("A")),
new Panel(title: "Middle", content: new ConsoleText("B")),
new Panel(title: "Right", content: new ConsoleText("C"))
);
column.Render();
// Alternatively through Fluent API:
Column fluentColumn = new Column(gap: 2)
.Add(new Panel(title: "Left", content: new ConsoleText("A")))
.Add(new Panel(title: "Middle", content: new ConsoleText("B")))
.Add(new Panel(title: "Right", content: new ConsoleText("C")));
fluentColumn.Render();using ConsolePrism.Layout;
using ConsolePrism.Components;
Panel mainContent = new(
title: "Dashboard",
content: new ConsoleText("Welcome to the application!"),
horizontalPadding: 2
);
// Wrap the content in the AppShell
AppShell shell = new(
title: "MY AWESOME CLI",
content: mainContent,
leftFooter: "Status: Online",
rightFooter: "v1.0.0 | Press ESC to exit"
);
shell.Render();using ConsolePrism.Core;
// Positioning
ConsoleHelper.WriteCentered("Centered Title");
ConsoleHelper.WriteRight("Right-aligned", padding: 2);
ConsoleHelper.WriteAt("Positioned text", x: 10, y: 5);
// Cursor control
ConsoleHelper.HideCursor();
ConsoleHelper.MoveCursor(0, 10);
ConsoleHelper.ShowCursor();
// Drawing
ConsoleHelper.DrawHorizontalLine('โ');
ConsoleHelper.WriteEmptyLines(2);- NordTheme - Arctic blue tones with rounded borders
- MonochromeTheme - Grayscale for minimal or accessible output
- RetroTheme - Amber tones with ASCII borders
- MatrixTheme - Cascading greens against a dark background
- SunsetTheme - Cosy oranges, magenta and soft whites to evoke a twilight atmosphere
- SolarizedTheme - Warm amber and earthy tones with cool accent colours
- PastelTheme - Muted, light tones for a gentle visual experience
using ConsolePrism.Themes;
using ConsolePrism.Themes.Presets;
// Apply globally
Theme.Apply(NordTheme.Instance);
// Reset to default
Theme.Apply(Theme.Default);using ConsolePrism.Themes;
Theme myTheme = new()
{
Colors = new ColorScheme
{
Primary = ConsoleColor.Cyan,
Success = ConsoleColor.Green,
Error = ConsoleColor.Red,
Warning = ConsoleColor.Yellow,
Info = ConsoleColor.Blue,
Highlight = ConsoleColor.Magenta,
Muted = ConsoleColor.DarkGray,
MenuTitle = ConsoleColor.Cyan,
MenuOption = ConsoleColor.White,
MenuSelected = ConsoleColor.Green,
MenuBorder = ConsoleColor.DarkGray,
TableHeader = ConsoleColor.Cyan,
TableBorder = ConsoleColor.DarkGray,
TableData = ConsoleColor.White,
ProgressBarComplete = ConsoleColor.Green,
ProgressBarIncomplete = ConsoleColor.DarkGray,
ProgressBarText = ConsoleColor.White
},
Border = BorderStyle.Rounded
};
Theme.Apply(myTheme);using ConsolePrism.Core;
using ConsolePrism.Themes.Presets;
// Theme.Current is temporarily replaced for the duration of the block
using (new ConsoleContext(MonochromeTheme.Instance))
{
table.Render();
}
// Theme.Current is automatically restored hereTable table = new(headers, data)
{
Theme = RetroTheme.Instance
};
table.Render(); // uses RetroTheme regardless of Theme.Currentusing ConsolePrism.Themes;
// Built-in presets
BorderStyle.Single; // โโโ โ โโโ (default)
BorderStyle.Double; // โโโ โ โโโ
BorderStyle.Rounded; // โญโโฎ โ โฐโโฏ
BorderStyle.Ascii; // +-+ | +-+
// Custom border
Borderstyle custom = new()
{
TopLeft = 'โ', TopRight = 'โ',
BottomLeft = 'โ', BottomRight = 'โ',
Horizontal = 'โ', Vertical = 'โ',
Cross = 'โฌ',
TeeLeft = 'โ ', TeeRight = 'โฃ',
TeeTop = 'โฆ', TeeBottom = 'โฉ'
};ConsolePrism/
โโโ Interfaces/
โ โโโ IRenderable โ Anything that can render itself
โ โโโ IInteractable โ Components that accept user input
โ โโโ IComponent โ Base interface for all UI components
| โโโ IRenderer โ Output backend abstraction
โ
โโโ Themes/
โ โโโ ColorScheme โ Full color palette definition
โ โโโ BorderStyle โ Border character set definition
โ โโโ Theme โ Unified theme object (ColorScheme + BorderStyle)
โ โโโ Presets/
โ
โโโ Core/
โ โโโ ColorWriter โ Semantic colored text output
โ โโโ ConsoleHelper โ Cursor control, positioning, and drawing utilities
โ โโโ ConsoleContext โ Scoped theme switching via IDisposable
โ โโโ Rendering/
โ โโโ ConsoleRenderer โ Default implementation writing to Console
โ โโโ StringRenderer โ In-memory buffer for testing and layout buffering
โ
โโโ Components/
| โโโ ComponentBase โ Abstract base with theme resolution and renderer swapping
โ โโโ Menu โ Numbered, interactive, and bordered menu styles
โ โโโ Table โ Auto-sizing bordered table with text wrapping
| โโโ TableCell โ Cell content with optional colour
โ โโโ ProgressBar โ Static and in-place animated progress bars
โ โโโ Spinner โ Animated spinners for async operations
โ โโโ Notification โ Transient styled messages with optional auto-dismiss
| โโโ ConsoleText โ Simple text for use with the layout components
โ โโโ Prompt โ Styled input prompt with optional masked entry
โ
โโโ Layout/
โโโ Panel โ Bordered content container with title support
โโโ Row โ Vertical component stacking with optional spacing
โโโ Column โ Horizontal side-by-side component layout
โโโ AppShell โ Common application layout with header, footer, and main content
โโโ Viewport โ Scrollable content region with fixed visible height
- .NET 9.0 or .NET 10.0
- Windows, macOS, or Linux
- A terminal with a dark background is recommended for the best visual experience
See LICENCE for details. (MIT Licence)
Contributions are welcome! You can:
- Report bugs or request features via Issues
- Submit pull requests
- Suggest improvements to the API
- Propose new components, themes, or layout containers